merging in from trunk before swapping out trunk

git-svn-id: https://svn.apache.org/repos/asf/directory/shared/branches/m1@1072787 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/all/pom.xml b/all/pom.xml
index 9f9f17a..8542e0e 100644
--- a/all/pom.xml
+++ b/all/pom.xml
@@ -51,11 +51,6 @@
 
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>shared-ldap</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
       <artifactId>shared-ldap-model</artifactId>
     </dependency>
 
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/AbstractStatefulDecoder.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/AbstractStatefulDecoder.java
deleted file mode 100644
index 74b8f3d..0000000
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/AbstractStatefulDecoder.java
+++ /dev/null
@@ -1,85 +0,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. 
- *  
- */
-package org.apache.directory.shared.asn1;
-
-
-/**
- * Convenience class to not have to re-implement the two setter methods every time
- * one starts a new decoder.
- * 
- * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
- */
-public abstract class AbstractStatefulDecoder implements StatefulDecoder
-{
-    /** this decoder's callback */
-    private DecoderCallback cb = null;
-
-
-    /**
-     * Creates a stateful decoder where the callback and monitor must be set.
-     */
-    public AbstractStatefulDecoder()
-    {
-    }
-
-
-    /**
-     * Creates a stateful decoder with a callback.
-     * 
-     * @param cb the callback to use for this decoder
-     */
-    public AbstractStatefulDecoder( DecoderCallback cb )
-    {
-        setCallback( cb );
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public void setCallback( DecoderCallback callback )
-    {
-        this.cb = callback;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public DecoderCallback getCallback()
-    {
-        return cb;
-    }
-
-
-    /**
-     * Notifies via the callback if one has been set that this decoder has
-     * decoded a unit of encoded data.
-     * 
-     * @param decoded the decoded byproduct.
-     */
-    protected void decodeOccurred( Object decoded )
-    {
-        if ( cb != null )
-        {
-            cb.decodeOccurred( this, decoded );
-        }
-    }
-}
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/BinaryDecoder.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/BinaryDecoder.java
deleted file mode 100755
index 26f6371..0000000
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/BinaryDecoder.java
+++ /dev/null
@@ -1,41 +0,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. 
- *  
- */
-
-package org.apache.directory.shared.asn1;
-
-
-/**
- * Defines common decoding methods for byte array decoders.
- * 
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- */
-public interface BinaryDecoder extends Decoder
-{
-    /**
-     * Decodes a byte array and returns the results as a byte array.
-     * 
-     * @param array A byte array which has been encoded with the appropriate encoder
-     * @return a byte array that contains decoded content
-     * @throws DecoderException
-     * A decoder exception is thrown if a Decoder encounters a
-     * failure condition during the decode process.
-     */
-    byte[] decode( byte[] array ) throws DecoderException;
-}
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/BinaryEncoder.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/BinaryEncoder.java
deleted file mode 100755
index ee365ca..0000000
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/BinaryEncoder.java
+++ /dev/null
@@ -1,41 +0,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. 
- *  
- */
-
-package org.apache.directory.shared.asn1;
-
-
-/**
- * Defines common encoding methods for byte array encoders.
- * 
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- */
-public interface BinaryEncoder extends Encoder
-{
-
-    /**
-     * Encodes a byte array and return the encoded data as a byte array.
-     * 
-     * @param array Data to be encoded
-     * @return A byte array containing the encoded data
-     * @throws EncoderException thrown if the Encoder encounters a failure condition during
-     * the encoding process.
-     */
-    byte[] encode( byte[] array ) throws EncoderException;
-}
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/DecoderCallback.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/DecoderCallback.java
deleted file mode 100644
index 1741ce5..0000000
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/DecoderCallback.java
+++ /dev/null
@@ -1,37 +0,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. 
- *  
- */
-package org.apache.directory.shared.asn1;
-
-
-/**
- * Callback interface for stateful decoder callbacks.
- * 
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- */
-public interface DecoderCallback
-{
-    /**
-     * Callback to deliver a fully decoded object.
-     * 
-     * @param decoder the stateful decoder driving the callback
-     * @param decoded the object that was decoded
-     */
-    void decodeOccurred( StatefulDecoder decoder, Object decoded );
-}
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/EncoderCallback.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/EncoderCallback.java
deleted file mode 100644
index bf0bad2..0000000
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/EncoderCallback.java
+++ /dev/null
@@ -1,37 +0,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. 
- *  
- */
-package org.apache.directory.shared.asn1;
-
-
-/**
- * Callback interface for stateful encoder callbacks.
- * 
- * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
- */
-public interface EncoderCallback
-{
-    /**
-     * Callback to deliver a fully encoded object.
-     * 
-     * @param encoder the stateful encoder driving the callback
-     * @param encoded the object that was encoded
-     */
-    void encodeOccurred( StatefulEncoder encoder, Object encoded );
-}
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/Hex.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/Hex.java
deleted file mode 100755
index 93fb78d..0000000
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/Hex.java
+++ /dev/null
@@ -1,231 +0,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. 
- *  
- */
-
-package org.apache.directory.shared.asn1;
-
-
-import org.apache.directory.shared.i18n.I18n;
-
-
-/**
- * Hex encoder and decoder.
- * 
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- */
-public class Hex implements BinaryEncoder, BinaryDecoder
-{
-    /** Used to build output as Hex */
-    private static final char[] DIGITS =
-        { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
-
-    /**
-     * Converts an array of characters representing hexidecimal values into an
-     * array of bytes of those same values. The returned array will be half the
-     * length of the passed array, as it takes two characters to represent any
-     * given byte. An exception is thrown if the passed char array has an odd
-     * number of elements.
-     * 
-     * @param data An array of characters containing hexidecimal digits
-     * @return A byte array containing binary data decoded from the supplied
-     * char array.
-     * @throws DecoderException Thrown if an odd number or illegal of characters is supplied
-     */
-    public static byte[] decodeHex( char[] data ) throws DecoderException
-    {
-        int len = data.length;
-
-        if ( ( len & 0x01 ) != 0 )
-        {
-            throw new DecoderException( I18n.err( I18n.ERR_00013_ODD_NUM_OF_CHARS ) );
-        }
-
-        byte[] out = new byte[len >> 1];
-
-        // two characters form the hex value.
-        for ( int i = 0, j = 0; j < len; i++ )
-        {
-            int f = toDigit( data[j], j ) << 4;
-            j++;
-            f |= toDigit( data[j], j );
-            j++;
-            out[i] = ( byte ) ( f & 0xFF );
-        }
-
-        return out;
-    }
-
-
-    /**
-     * Converts a hexadecimal character to an integer.
-     * 
-     * @param ch A character to convert to an integer digit
-     * @param index The index of the character in the source
-     * @return An integer
-     * @throws DecoderException Thrown if ch is an illegal hex character
-     */
-    private static int toDigit( char ch, int index ) throws DecoderException
-    {
-        int digit = Character.digit( ch, 16 );
-
-        if ( digit == -1 )
-        {
-            throw new DecoderException( I18n.err( I18n.ERR_00014_ILLEGAL_HEX_CHAR, ch, index ) );
-        }
-
-        return digit;
-    }
-
-
-    /**
-     * Converts an array of bytes into an array of characters representing the
-     * hexidecimal 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 hexidecimal 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++] = DIGITS[( 0xF0 & data[i] ) >>> 4];
-            out[j++] = DIGITS[0x0F & data[i]];
-        }
-
-        return out;
-    }
-
-
-    /**
-     * Converts an array of character bytes representing hexidecimal values into
-     * an array of bytes of those same values. The returned array will be half
-     * the length of the passed array, as it takes two characters to represent
-     * any given byte. An exception is thrown if the passed char array has an
-     * odd number of elements.
-     * 
-     * @param array An array of character bytes containing hexidecimal digits
-     * @return A byte array containing binary data decoded from the supplied
-     * byte array (representing characters).
-     * @throws DecoderException Thrown if an odd number of characters is supplied to this
-     * function
-     * @see #decodeHex(char[])
-     */
-    public byte[] decode( byte[] array ) throws DecoderException
-    {
-        return decodeHex( new String( array ).toCharArray() );
-    }
-
-
-    /**
-     * Converts a String or an array of character bytes representing hexidecimal
-     * values into an array of bytes of those same values. The returned array
-     * will be half the length of the passed String or array, as it takes two
-     * characters to represent any given byte. An exception is thrown if the
-     * passed char array has an odd number of elements.
-     * 
-     * @param object A String or, an array of character bytes containing
-     * hexadecimal digits
-     * @return A byte array containing binary data decoded from the supplied
-     * byte array (representing characters).
-     * @throws DecoderException Thrown if an odd number of characters is supplied to this
-     * function or the object is not a String or char[]
-     * @see #decodeHex(char[])
-     */
-    public Object decode( Object object ) throws DecoderException
-    {
-        try
-        {
-            char[] charArray = null;
-
-            if ( object instanceof String )
-            {
-                charArray = ( ( String ) object ).toCharArray();
-            }
-            else
-            {
-                charArray = ( char[] ) object;
-            }
-
-            return decodeHex( charArray );
-        }
-        catch ( ClassCastException e )
-        {
-            throw new DecoderException( e.getMessage() );
-        }
-    }
-
-
-    /**
-     * Converts an array of bytes into an array of bytes for the characters
-     * representing the hexidecimal 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 array a byte[] to convert to Hex characters
-     * @return A byte[] containing the bytes of the hexidecimal characters
-     * @see #encodeHex(byte[])
-     */
-    public byte[] encode( byte[] array )
-    {
-        return new String( encodeHex( array ) ).getBytes();
-    }
-
-
-    /**
-     * Converts a String or an array of bytes into an array of characters
-     * representing the hexidecimal values of each byte in order. The returned
-     * array will be double the length of the passed String or array, as it
-     * takes two characters to represent any given byte.
-     * 
-     * @param object a String, or byte[] to convert to Hex characters
-     * @return A char[] containing hexidecimal characters
-     * @throws org.apache.directory.shared.asn1.EncoderException Thrown if the given object is not a String or byte[]
-     * @see #encodeHex(byte[])
-     */
-    public Object encode( Object object ) throws EncoderException
-    {
-        try
-        {
-            byte[] byteArray = null;
-
-            if ( object instanceof String )
-            {
-                byteArray = ( ( String ) object ).getBytes();
-            }
-            else
-            {
-                byteArray = ( byte[] ) object;
-            }
-
-            return encodeHex( byteArray );
-        }
-        catch ( ClassCastException e )
-        {
-            throw new EncoderException( e.getMessage() );
-        }
-    }
-}
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/StatefulDecoder.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/StatefulDecoder.java
deleted file mode 100644
index c50a6d3..0000000
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/StatefulDecoder.java
+++ /dev/null
@@ -1,62 +0,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. 
- *  
- */
-package org.apache.directory.shared.asn1;
-
-
-/**
- * A decoder which decodes encoded data as it arrives in pieces while
- * maintaining the state of the decode operation between the arrival of encoded
- * chunks. As chunks of encoded data arrive the decoder processes each chunk of
- * encoded data and maintains decoding state in between arrivals: it is hence
- * stateful and should be associated with a single channel or encoded data
- * producer. When an arbitrary unit of encoding, to be determined by the
- * encoding scheme, has been decoded, the <code>decode()</code> method of the
- * registered DecoderCallback is called.
- * 
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- */
-public interface StatefulDecoder
-{
-    /**
-     * Decodes a piece of encoded data. The nature of this call, synchronous
-     * verses asyncrhonous, with respect to driving the actual decoding of the
-     * encoded data argument is determined by an implementation. A return from
-     * this method does not guarantee any callbacks: zero or more callbacks may
-     * occur during this call.
-     * 
-     * @param encoded an object representing a piece of encoded data
-     * @throws org.apache.directory.shared.asn1.DecoderException if the encoded element can't be decoded
-     */
-    void decode( Object encoded ) throws DecoderException;
-
-
-    /**
-     * Sets the callback for this StatefulDecoder.
-     * 
-     * @param cb the callback to inform of a complete decode operation
-     */
-    void setCallback( DecoderCallback cb );
-
-
-    /**
-     * @return The decoder callback
-     */
-    DecoderCallback getCallback();
-}
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/StatefulEncoder.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/StatefulEncoder.java
deleted file mode 100644
index 7882a13..0000000
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/StatefulEncoder.java
+++ /dev/null
@@ -1,48 +0,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. 
- *  
- */
-package org.apache.directory.shared.asn1;
-
-
-/**
- * The StatefulEncoder interface.
- * 
- * @author <a href="mailto:dev@directory.apache.org"> Apache Directory Project</a>
- */
-public interface StatefulEncoder
-{
-    /**
-     * Encodes a Message object piece by piece often emitting chunks of the
-     * final PDU to the callback if present.
-     * 
-     * @param obj the message object to encode into a PDU
-     * @throws EncoderException if there are problems while encoding
-     */
-    void encode( Object obj ) throws EncoderException;
-
-
-    /**
-     * Sets the callback of the underlying implementation. There is no need for
-     * any special callbacks because when encoding we do not need to transform
-     * before a value return as we did in the decoder.
-     * 
-     * @param cb the callback to set on the underlying provider specific encoder
-     */
-    void setCallback( EncoderCallback cb );
-}
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/Asn1StringUtils.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/Asn1StringUtils.java
index fae1754..a691ac9 100644
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/Asn1StringUtils.java
+++ b/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/Asn1StringUtils.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.util;
 
@@ -25,7 +25,7 @@
 
 /**
  * Little helper class.
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 public final class Asn1StringUtils
@@ -42,17 +42,8 @@
 
 
     /**
-     * This is a helper class, there is no reason to define a public constructor for it.
-     */
-    private Asn1StringUtils()
-    {
-        // Do nothing
-    }
-
-
-    /**
      * Helper function that dump a byte in hex form
-     * 
+     *
      * @param octet The byte to dump
      * @return A string representation of the byte
      */
@@ -65,7 +56,7 @@
 
     /**
      * 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
      */
@@ -90,7 +81,7 @@
 
     /**
      * 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
      */
@@ -116,7 +107,7 @@
     /**
      * 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
      */
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/BitString.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/BitString.java
index a608cd1..0a128db 100644
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/BitString.java
+++ b/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/BitString.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.util;
 
@@ -28,7 +28,7 @@
 /**
  * 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 implements Serializable
@@ -55,7 +55,7 @@
     /**
      * 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 )
@@ -85,7 +85,7 @@
     /**
      * Creates a BitString from a byte[]. As the first byteis 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
      */
@@ -104,7 +104,7 @@
     /**
      * Set a new BitString in the BitString. It will replace the old BitString,
      * and reset the current length with the new one.
-     * 
+     *
      * @param bytes The string to store
      */
     public void setData( byte[] bytes )
@@ -132,7 +132,7 @@
     /**
      * 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()
@@ -148,7 +148,7 @@
 
     /**
      * Get the number of unused bits
-     * 
+     *
      * @return A byte which represent the number of unused bits
      */
     public byte getUnusedBits()
@@ -158,10 +158,10 @@
 
 
     /**
-     * Set a bit at a specified position. 
+     * 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 )
@@ -180,11 +180,11 @@
 
 
     /**
-     * Clear a bit at a specified position. 
+     * 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 
+     * 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 )
@@ -203,24 +203,23 @@
 
 
     /**
-     * Get the bit stored into the BitString at a specific position. 
+     * 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
-     * For instance, if we have 10 bits, then they are coded as 
+     * 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
-     * 
-     * With '1001 000x', where x is an unused bit, 
-     *       ^ ^    ^ 
-     *       | |    | 
-     *       | |    |  
-     *       | |    +----- getBit(6) = 0 
-     *       | +---------- getBit(2) = 0 
+     * <pre>
+     * With '1001 000x', where x is an unused bit,
+     *       ^ ^    ^
+     *       | |    |
+     *       | |    |
+     *       | |    +----- getBit(6) = 0
+     *       | +---------- getBit(2) = 0
      *       +------------ getBit(0) = 1
-     *       
-     * @param pos The position of the requested bit.  
-     * 
-     * @return <code>true</code> if the bit is set, <code>false</code>
-     *         otherwise
+     * </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 )
     {
@@ -234,7 +233,7 @@
         byte mask = (byte)( 1 << bitNumber );
 
         int res = bytes[posBytes] & mask;
-        
+
         return res != 0;
     }
 
@@ -250,9 +249,10 @@
 
     /**
      * Return a native String representation of the BitString.
-     * 
+     *
      * @return A String representing the BitString
      */
+    @Override
     public String toString()
     {
         StringBuilder sb = new StringBuilder();
diff --git a/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/OID.java b/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/OID.java
index 1ac9b3c..7856323 100644
--- a/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/OID.java
+++ b/asn1-api/src/main/java/org/apache/directory/shared/asn1/util/OID.java
@@ -28,35 +28,40 @@
 
 
 /**
- * This class implement an OID (Object Identifier).
- *
- * An OID is encoded as a list of bytes representing integers.
- *
- * An OID has a numeric representation where number are separated with dots :
- * SPNEGO Oid = 1.3.6.1.5.5.2
- *
- * Translating from a byte list to a dot separated list of number follows the rules :
- * - the first number is in [0..2]
- * - the second number is in [0..39] if the first number is 0 or 1
- * - the first byte has a value equal to : number 1 * 40 + number two
- * - the upper bit of a byte is set if the next byte is a part of the number
- *
- * For instance, the SPNEGO Oid (1.3.6.1.5.5.2) will be encoded :
+ * This class implement an OID (Object Identifier).<br/>
+ * <br/>
+ * An OID is encoded as a list of bytes representing integers.<br/>
+ * <br/>
+ * An OID has a numeric representation where number are separated with dots :<br/>
+ * SPNEGO Oid = 1.3.6.1.5.5.2<br/>
+ * <br/>
+ * Translating from a byte list to a dot separated list of number follows the rules :<br/>
+ * <ul>
+ * <li>the first number is in [0..2]</li>
+ * <li>the second number is in [0..39] if the first number is 0 or 1</li>
+ * <li>the first byte has a value equal to : number 1 * 40 + number two</li>
+ * <li>the upper bit of a byte is set if the next byte is a part of the number</li>
+ * </ul>
+ * <br/>
+ * For instance, the SPNEGO Oid (1.3.6.1.5.5.2) will be encoded :<br/>
+ * <pre>
  * 1.3 -> 0x2B (1*40 + 3 = 43 = 0x2B)
  * .6  -> 0x06
  * .1  -> 0x01
  * .5  -> 0x05
  * .5  -> 0x05
  * .2  -> 0x02
- *
- * The Kerberos V5 Oid (1.2.840.48018.1.2.2)  will be encoded :
+ * </pre>
+ * <br/>
+ * The Kerberos V5 Oid (1.2.840.48018.1.2.2)  will be encoded :<br/>
+ * <pre>
  * 1.2   -> 0x2A (1*40 + 2 = 42 = 0x2A)
  * 840   -> 0x86 0x48 (840 = 6 * 128 + 72 = (0x06 | 0x80) 0x48 = 0x86 0x48
  * 48018 -> 0x82 0xF7 0x12 (2 * 128 * 128 + 119 * 128 + 18 = (0x02 | 0x80) (0x77 | 0x80) 0x12
  * .1    -> 0x01
  * .2    -> 0x02
  * .2    -> 0x02
- *
+ * </pre>
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 public class OID implements Serializable
@@ -294,7 +299,7 @@
                     throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oid ) );
                 }
 
-                if ( ituOrIso && value > 39 )
+                if ( ituOrIso && ( value > 39 ) )
                 {
                     throw new DecoderException( I18n.err( I18n.ERR_00033_INVALID_OID, oid ) );
                 }
@@ -596,7 +601,7 @@
                     return false;
                 }
 
-                if ( ituOrIso && value > 39 )
+                if ( ituOrIso && ( value > 39 ) )
                 {
                     return false;
                 }
@@ -631,6 +636,7 @@
      *
      * @return A String representing the OID
      */
+    @Override
     public String toString()
     {
         StringBuffer sb = new StringBuffer();
@@ -652,6 +658,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public int hashCode()
     {
         return hash;
@@ -661,6 +668,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean equals( Object oid )
     {
         if ( this == oid )
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadBitString.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadBitString.java
index 6aefd37..468b793 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadBitString.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadBitString.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.actions;
 
@@ -32,10 +32,10 @@
 
 /**
  * The action used read a BITSTRING from a TLV
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public abstract class AbstractReadBitString extends GrammarAction<Asn1Container>
+public abstract class AbstractReadBitString<E extends Asn1Container> extends GrammarAction<E>
 {
     /** The logger */
     private static final Logger LOG = LoggerFactory.getLogger( AbstractReadBitString.class );
@@ -55,18 +55,18 @@
 
     /**
      * gives a byte array to be set to the appropriate field of the ASN.1 object
-     * present in the container 
+     * 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, Asn1Container container );
+    protected abstract void setBitString( byte[] data, E container );
 
 
     /**
      * {@inheritDoc}
      */
-    public final void action( Asn1Container container ) throws DecoderException
+    public final void action( E container ) throws DecoderException
     {
         TLV tlv = container.getCurrentTLV();
 
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadInteger.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadInteger.java
index d5e3e31..128d936 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadInteger.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadInteger.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.actions;
 
@@ -23,10 +23,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
 import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
 import org.apache.directory.shared.asn1.ber.tlv.Value;
-import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.util.Strings;
 import org.slf4j.Logger;
@@ -35,10 +35,10 @@
 
 /**
  * The action used to read an integer value
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public abstract class AbstractReadInteger extends GrammarAction<Asn1Container>
+public abstract class AbstractReadInteger<E extends Asn1Container> extends GrammarAction<E>
 {
     /** The logger */
     private static final Logger LOG = LoggerFactory.getLogger( AbstractReadInteger.class );
@@ -63,7 +63,7 @@
 
 
     /**
-     * 
+     *
      * Creates a new instance of AbstractReadInteger.
      *
      * @param name the action's name
@@ -80,19 +80,19 @@
 
 
     /**
-     * 
+     *
      * 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, Asn1Container container );
+    protected abstract void setIntegerValue( int value, E container );
 
 
     /**
      * {@inheritDoc}
      */
-    public final void action( Asn1Container container ) throws DecoderException
+    public final void action( E container ) throws DecoderException
     {
         TLV tlv = container.getCurrentTLV();
 
@@ -104,9 +104,9 @@
             // This will generate a PROTOCOL_ERROR
             throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
         }
-        
+
         Value value = tlv.getValue();
-        
+
         try
         {
             int number = IntegerDecoder.parse( value, minValue, maxValue );
@@ -115,7 +115,7 @@
             {
                 LOG.debug( "read integer value : {}", number );
             }
-            
+
             setIntegerValue( number, container );
         }
         catch ( IntegerDecoderException ide )
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadOctetString.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadOctetString.java
index c2fa52d..1a87d3e 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadOctetString.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/AbstractReadOctetString.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.actions;
 
@@ -32,10 +32,10 @@
 
 /**
  * The action used to read an OCTET STRING value
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public abstract class AbstractReadOctetString extends GrammarAction<Asn1Container>
+public abstract class AbstractReadOctetString<E extends Asn1Container> extends GrammarAction<E>
 {
     /** The logger */
     private static final Logger LOG = LoggerFactory.getLogger( AbstractReadOctetString.class );
@@ -55,32 +55,32 @@
 
     /**
      * Instantiates a new AbstractReadInteger action.
-     * 
+     *
      * @param name The log message
      * @param canBeNull Tells if the byte array can be null or not
      */
     public AbstractReadOctetString( String name, boolean canBeNull )
     {
         super( name );
-        
+
         this.canBeNull = canBeNull;
     }
 
 
     /**
-     * 
+     *
      * set 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, Asn1Container container );
+    protected abstract void setOctetString( byte[] value, E container );
 
 
     /**
      * {@inheritDoc}
      */
-    public final void action( Asn1Container container ) throws DecoderException
+    public final void action( E container ) throws DecoderException
     {
         TLV tlv = container.getCurrentTLV();
 
@@ -92,9 +92,9 @@
             // This will generate a PROTOCOL_ERROR
             throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
         }
-        
+
         Value value = tlv.getValue();
-        
+
         // The data should not be null
         if ( ( value.getData() == null ) && ( !canBeNull ) )
         {
@@ -103,7 +103,7 @@
             // This will generate a PROTOCOL_ERROR
             throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
         }
-        
+
         setOctetString( value.getData(), container );
     }
 }
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/CheckNotNullLength.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/CheckNotNullLength.java
index 9775340..9093dc0 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/CheckNotNullLength.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/actions/CheckNotNullLength.java
@@ -6,24 +6,24 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.actions;
 
 
+import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
-import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.i18n.I18n;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -31,10 +31,10 @@
 
 /**
  * An action that checks the length is not null
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class CheckNotNullLength extends GrammarAction<Asn1Container>
+public class CheckNotNullLength<E extends Asn1Container> extends GrammarAction<E>
 {
     /** The logger */
     private static final Logger LOG = LoggerFactory.getLogger( CheckNotNullLength.class );
@@ -51,7 +51,7 @@
     /**
      * {@inheritDoc}
      */
-    public void action( Asn1Container container ) throws DecoderException
+    public void action( E container ) throws DecoderException
     {
         TLV tlv = container.getCurrentTLV();
 
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/AbstractContainer.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/AbstractContainer.java
index 258d5d2..ac74e27 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/AbstractContainer.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/AbstractContainer.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.ber;
 
@@ -32,13 +32,13 @@
  * 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 */
-    protected Grammar grammar;
+    protected Grammar<?> grammar;
 
     /** Store a stack of the current states used when switching grammars */
     protected int[] stateStack;
@@ -69,9 +69,9 @@
 
     /** The Stream being decoded */
     private ByteBuffer stream;
-    
-    /** A flag telling if the Value should be accumulated before being decoded 
-     * for constructed types */ 
+
+    /** A flag telling if the Value should be accumulated before being decoded
+     * for constructed types */
     private boolean isGathering = false;
 
     /**
@@ -83,25 +83,25 @@
         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 ) 
+    protected AbstractContainer( ByteBuffer stream )
     {
         state = TLVStateEnum.TAG_STATE_START;
         this.stream = stream;
     }
 
-    
+
     /**
      * Get the current grammar
-     * 
+     *
      * @return Returns the grammar used to decode a LdapMessage.
      */
-    public Grammar getGrammar()
+    public Grammar<?> getGrammar()
     {
         return grammar;
     }
@@ -109,7 +109,7 @@
 
     /**
      * Get the current grammar state
-     * 
+     *
      * @return Returns the current grammar state
      */
     public TLVStateEnum getState()
@@ -120,7 +120,7 @@
 
     /**
      * Set the new current state
-     * 
+     *
      * @param state The new state
      */
     public void setState( TLVStateEnum state )
@@ -131,7 +131,7 @@
 
     /**
      * Check that we can have a end state after this transition
-     * 
+     *
      * @return true if this can be the last transition
      */
     public boolean isGrammarEndAllowed()
@@ -142,7 +142,7 @@
 
     /**
      * Set the flag to allow a end transition
-     * 
+     *
      * @param grammarEndAllowed true or false, depending on the next transition
      * being an end or not.
      */
@@ -154,7 +154,7 @@
 
     /**
      * Get the transition
-     * 
+     *
      * @return Returns the transition from the previous state to the new state
      */
     public Enum<?> getTransition()
@@ -165,7 +165,7 @@
 
     /**
      * Update the transition from a state to another
-     * 
+     *
      * @param transition The transition to set
      */
     public void setTransition( Enum<?> transition )
@@ -176,7 +176,7 @@
 
     /**
      * Set the current TLV
-     * 
+     *
      * @param currentTLV The current TLV
      */
     public void setCurrentTLV( TLV currentTLV )
@@ -187,7 +187,7 @@
 
     /**
      * Get the current TLV
-     * 
+     *
      * @return Returns the current TLV being decoded
      */
     public TLV getCurrentTLV()
@@ -198,7 +198,7 @@
 
     /**
      * Get the parent TLV;
-     * 
+     *
      * @return Returns the parent TLV, if any.
      */
     public TLV getParentTLV()
@@ -209,7 +209,7 @@
 
     /**
      * Set the parent TLV.
-     * 
+     *
      * @param parentTLV The parent TLV to set.
      */
     public void setParentTLV( TLV parentTLV )
@@ -232,7 +232,7 @@
 
     /**
      * Return a new ID and increment the counter
-     * @return A new TLV id. 
+     * @return A new TLV id.
      */
     public int getNewTlvId()
     {
@@ -295,8 +295,8 @@
             this.maxPDUSize = Integer.MAX_VALUE;
         }
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
@@ -304,8 +304,8 @@
     {
         return stream;
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
@@ -314,30 +314,30 @@
         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;
     }
 
@@ -349,7 +349,7 @@
     {
         return isGathering;
     }
-    
+
 
     /**
      * {@inheritDoc}
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/Asn1Container.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/Asn1Container.java
index fb7081e..88f1c48 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/Asn1Container.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/Asn1Container.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.ber;
 
@@ -29,30 +29,30 @@
 
 /**
  * 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 );
-    
-    
+
+
     /**
      * Get the current grammar state
-     * 
+     *
      * @return Returns the current grammar state
      */
     TLVStateEnum getState();
@@ -60,7 +60,7 @@
 
     /**
      * Set the new current state
-     * 
+     *
      * @param state The new state
      */
     void setState( TLVStateEnum state );
@@ -68,7 +68,7 @@
 
     /**
      * Get the currentTLV
-     * 
+     *
      * @return Returns the current TLV being decoded
      */
     TLV getCurrentTLV();
@@ -76,7 +76,7 @@
 
     /**
      * Set the current TLV
-     * 
+     *
      * @param tlv The current TLV
      */
     void setCurrentTLV( TLV tlv );
@@ -84,7 +84,7 @@
 
     /**
      * Get the grammar
-     * 
+     *
      * @return Returns the grammar used to decode a LdapMessage.
      */
     Grammar getGrammar();
@@ -92,7 +92,7 @@
 
     /**
      * Get the transition
-     * 
+     *
      * @return Returns the transition from the previous state to the new state
      */
     Enum<?> getTransition();
@@ -100,7 +100,7 @@
 
     /**
      * Update the transition from a state to another
-     * 
+     *
      * @param transition The transition to set
      */
     void setTransition( Enum<?> transition );
@@ -114,7 +114,7 @@
 
     /**
      * Set the parent TLV
-     * 
+     *
      * @param parentTLV The new parent TLV
      */
     void setParentTLV( TLV parentTLV );
@@ -122,7 +122,7 @@
 
     /**
      * Check that we can have a end state after this transition
-     * 
+     *
      * @return true if this can be the last transition
      */
     boolean isGrammarEndAllowed();
@@ -130,7 +130,7 @@
 
     /**
      * Set the flag to allow a end transition
-     * 
+     *
      * @param grammarEndAllowed true or false, depending on the next transition
      * being an end or not.
      */
@@ -178,8 +178,8 @@
      * 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
@@ -187,22 +187,22 @@
      * @param tlv The TLV to rollback
      */
     void rewind();
-    
-    
+
+
     /**
      * Look for the closest parent which has an expected length above 0
      */
     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 
+     * 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
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/AbstractGrammar.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/AbstractGrammar.java
index 57c8806..d48be3c 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/AbstractGrammar.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/AbstractGrammar.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.ber.grammar;
 
@@ -31,10 +31,10 @@
 /**
  * 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
+public abstract class AbstractGrammar<E extends Asn1Container> implements Grammar<E>
 {
     /** The logger */
     private static final Logger LOG = LoggerFactory.getLogger( AbstractGrammar.class );
@@ -47,7 +47,7 @@
      * indice the states, the second dimension indices the Tag value, so it is
      * 256 wide.
      */
-    protected GrammarTransition<Asn1Container>[][] transitions;
+    protected GrammarTransition<E>[][] transitions;
 
     /** The grammar name */
     private String name;
@@ -60,7 +60,7 @@
 
     /**
      * Return the grammar's name
-     * 
+     *
      * @return The grammar name
      */
     public String getName()
@@ -71,7 +71,7 @@
 
     /**
      * Set the grammar's name
-     * 
+     *
      * @param name The new grammar name
      */
     public void setName( String name )
@@ -82,12 +82,12 @@
 
     /**
      * 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<Asn1Container> getTransition( Enum<?> state, int tag )
+    public GrammarTransition<E> getTransition( Enum<?> state, int tag )
     {
         return transitions[state.ordinal()][tag & 0x00FF];
     }
@@ -96,11 +96,11 @@
     /**
      * The main function. This is where an action is executed. If the action is
      * null, nothing is done.
-     * 
+     *
      * @param container The Asn1Container
      * @throws DecoderException Thrown if anything went wrong
      */
-    public void executeAction( Asn1Container container ) throws DecoderException
+    public void executeAction( E container ) throws DecoderException
     {
 
         Enum<?> currentState = container.getTransition();
@@ -113,7 +113,7 @@
         byte tagByte = container.getCurrentTLV().getTag();
 
         // We will loop until no more actions are to be executed
-        GrammarTransition<Asn1Container> transition = ( ( AbstractGrammar ) container.getGrammar() ).getTransition( currentState,
+        GrammarTransition<E> transition = ( ( AbstractGrammar<E> ) container.getGrammar() ).getTransition( currentState,
             tagByte );
 
         if ( transition == null )
@@ -134,7 +134,7 @@
 
         if ( transition.hasAction() )
         {
-            Action<Asn1Container> action = transition.getAction();
+            Action<E> action = transition.getAction();
             action.action( container );
         }
 
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/Grammar.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/Grammar.java
index c2dd240..a7bc93d 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/Grammar.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/Grammar.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.ber.grammar;
 
@@ -26,24 +26,24 @@
 
 /**
  * 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
+public interface Grammar<E 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( Asn1Container asn1Container ) throws DecoderException;
+    void executeAction( E asn1Container ) throws DecoderException;
 
 
     /**
      * Get the grammar name
-     * 
+     *
      * @return Return the grammar's name
      */
     String getName();
@@ -51,7 +51,7 @@
 
     /**
      * Set the grammar's name
-     * 
+     *
      * @param name The grammar name
      */
     void setName( String name );
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/GrammarTransition.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/GrammarTransition.java
index 6d5b999..36d4492 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/GrammarTransition.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/grammar/GrammarTransition.java
@@ -6,28 +6,29 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.ber.grammar;
 
 
 import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
 import org.apache.directory.shared.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.
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 public class GrammarTransition<E extends Asn1Container>
@@ -47,7 +48,7 @@
 
     /**
      * Creates a new GrammarTransition object.
-     * 
+     *
      * @param previousState the previous state
      * @param currentState The current state
      * @param currentTag the current TLV's tag
@@ -63,8 +64,55 @@
 
 
     /**
+     * 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<E> 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()
@@ -104,6 +152,7 @@
      * @param statesEnum Starting state.
      * @return A representation of the transition as a string.
      */
+    @Override
     public String toString( )
     {
         StringBuilder sb = new StringBuilder();
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/BooleanDecoder.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/BooleanDecoder.java
index 9156126..0cfd7e1 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/BooleanDecoder.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/BooleanDecoder.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.ber.tlv;
 
@@ -27,7 +27,7 @@
 
 /**
  * Parse and decode a Boolean value.
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 public final class BooleanDecoder
@@ -37,17 +37,8 @@
 
 
     /**
-     * This is a helper class, there is no reason to define a public constructor for it.
-     */
-    private BooleanDecoder()
-    {
-        // Do nothing
-    }
-
-
-    /**
      * Parse a byte buffer and send back a booelan.
-     * 
+     *
      * @param value The byte buffer to parse
      * @return A boolean.
      * @throws BooleanDecoderException Thrown if the byte stream does not contains a boolean
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/IntegerDecoder.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/IntegerDecoder.java
index ac4ad48..ed21aea 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/IntegerDecoder.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/IntegerDecoder.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.ber.tlv;
 
@@ -25,7 +25,7 @@
 
 /**
  * Parse and decode an Integer value.
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 public final class IntegerDecoder
@@ -36,18 +36,9 @@
 
 
     /**
-     * This is a helper class, there is no reason to define a public constructor for it.
-     */
-    private IntegerDecoder()
-    {
-        // Do nothing
-    }
-
-
-    /**
      * Parse a byte buffer and send back an integer, 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
@@ -94,7 +85,7 @@
 
     /**
      * 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
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/LongDecoder.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/LongDecoder.java
index 9f515a4..f3360e2 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/LongDecoder.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/LongDecoder.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.ber.tlv;
 
@@ -25,7 +25,7 @@
 
 /**
  * Parse and decode a Long value.
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 public final class LongDecoder
@@ -37,18 +37,9 @@
 
 
     /**
-     * This is a helper class, there is no reason to define a public constructor for it.
-     */
-    private LongDecoder()
-    {
-        // Do nothing
-    }
-
-
-    /**
      * 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
@@ -94,7 +85,7 @@
 
     /**
      * 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
diff --git a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/Value.java b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/Value.java
index 1fa5bd6..2d83eb2 100644
--- a/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/Value.java
+++ b/asn1-ber/src/main/java/org/apache/directory/shared/asn1/ber/tlv/Value.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.asn1.ber.tlv;
 
@@ -25,15 +25,15 @@
 import java.nio.ByteBuffer;
 
 import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.util.Asn1StringUtils;
 import org.apache.directory.shared.asn1.util.BitString;
 import org.apache.directory.shared.asn1.util.OID;
-import org.apache.directory.shared.asn1.util.Asn1StringUtils;
 import org.apache.directory.shared.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 Value implements Serializable
@@ -106,7 +106,7 @@
 
     /**
      * Creates a new Value from a byte[]
-     * 
+     *
      * @param value the associated value
      */
     public Value( byte[] value )
@@ -130,7 +130,7 @@
 
     /**
      * Initialize the Value
-     * 
+     *
      * @param size The data size to allocate.
      */
     public void init( int size )
@@ -152,7 +152,7 @@
 
     /**
      * Get the Values'data
-     * 
+     *
      * @return Returns the data.
      */
     public byte[] getData()
@@ -163,7 +163,7 @@
 
     /**
      * Set a block of bytes in the Value
-     * 
+     *
      * @param data The data to set.
      */
     public void setData( ByteBuffer data )
@@ -176,7 +176,7 @@
 
     /**
      * Append some bytes to the data buffer.
-     * 
+     *
      * @param buffer The data to append.
      */
     public void addData( ByteBuffer buffer )
@@ -189,7 +189,7 @@
 
     /**
      * Set a block of bytes in the Value
-     * 
+     *
      * @param data The data to set.
      */
     public void setData( byte[] data )
@@ -201,7 +201,7 @@
 
     /**
      * Append some bytes to the data buffer.
-     * 
+     *
      * @param array The data to append.
      */
     public void addData( byte[] array )
@@ -224,21 +224,21 @@
      * 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 )
+        if ( ( value >= ONE_BYTE_MIN ) && ( value <= ONE_BYTE_MAX ) )
         {
             return 1;
         }
-        else if ( value >= TWO_BYTE_MIN && value <= TWO_BYTE_MAX )
+        else if ( ( value >= TWO_BYTE_MIN ) && ( value <= TWO_BYTE_MAX ) )
         {
             return 2;
         }
-        else if ( value >= THREE_BYTE_MIN && value <= THREE_BYTE_MAX )
+        else if ( ( value >= THREE_BYTE_MIN ) && ( value <= THREE_BYTE_MAX ) )
         {
             return 3;
         }
@@ -253,37 +253,37 @@
      * 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 )
+        if ( ( value >= ONE_BYTE_MIN ) && ( value <= ONE_BYTE_MAX ) )
         {
             return 1;
         }
-        else if ( value >= TWO_BYTE_MIN && value <= TWO_BYTE_MAX )
+        else if ( ( value >= TWO_BYTE_MIN ) && ( value <= TWO_BYTE_MAX ) )
         {
             return 2;
         }
-        else if ( value >= THREE_BYTE_MIN && value <= THREE_BYTE_MAX )
+        else if ( ( value >= THREE_BYTE_MIN ) && ( value <= THREE_BYTE_MAX ) )
         {
             return 3;
         }
-        else if ( value >= FOUR_BYTE_MIN && value <= FOUR_BYTE_MAX )
+        else if ( ( value >= FOUR_BYTE_MIN ) && ( value <= FOUR_BYTE_MAX ) )
         {
             return 4;
         }
-        else if ( value >= FIVE_BYTE_MIN && value <= FIVE_BYTE_MAX )
+        else if ( ( value >= FIVE_BYTE_MIN ) && ( value <= FIVE_BYTE_MAX ) )
         {
             return 5;
         }
-        else if ( value >= SIX_BYTE_MIN && value <= SIX_BYTE_MAX )
+        else if ( ( value >= SIX_BYTE_MIN ) && ( value <= SIX_BYTE_MAX ) )
         {
             return 6;
         }
-        else if ( value >= SEVEN_BYTE_MIN && value <= SEVEN_BYTE_MAX )
+        else if ( ( value >= SEVEN_BYTE_MIN ) && ( value <= SEVEN_BYTE_MAX ) )
         {
             return 7;
         }
@@ -296,17 +296,19 @@
 
     /**
      * Utility function that return a byte array representing the Value We must
-     * respect the ASN.1 BER encoding scheme : 
-     * 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 
+     * 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.
      */
@@ -395,64 +397,66 @@
     /**
      * Utility function that return a byte array representing the Value.
      * We must respect the ASN.1 BER encoding scheme : <br>
-     * 1) positive integer <br>
-     * - [0 - 0x7F] : 0xVV <br>
-     * - [0x80 - 0xFF] : 0x00 0xVV <br>
-     * - [0x0100 - 0x7FFF] : 0xVV 0xVV <br>
-     * - [0x8000 - 0xFFFF] : 0x00 0xVV 0xVV <br>
-     * - [0x010000 - 0x7FFFFF] : 0xVV 0xVV 0xVV <br>
-     * - [0x800000 - 0xFFFFFF] : 0x00 0xVV 0xVV 0xVV <br>
-     * - [0x01000000 - 0x7FFFFFFF] : 0xVV 0xVV 0xVV 0xVV <br>
-     * 2) Negative number - (~value) + 1 <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>
-     *   -1                      -> FF FF FF FF FF FF FF [FF]<br>
-     *   -127                    -> FF FF FF FF FF FF FF [81]<br>
-     *   -128                    -> FF FF FF FF FF FF FF [80]<br>
-     *   -129                    -> FF FF FF FF FF FF [FF 7F]<br>
-     *   -255                    -> FF FF FF FF FF FF [FF 01]<br>
-     *   -256                    -> FF FF FF FF FF FF [FF 00]<br>
-     *   -257                    -> FF FF FF FF FF FF [FE FF]<br>
-     *   -32767                  -> FF FF FF FF FF FF [80 01]<br>
-     *   -32768                  -> FF FF FF FF FF FF [80 00]<br>
-     *   -32769                  -> FF FF FF FF FF [FF 7F FF]<br>
-     *   -65535                  -> FF FF FF FF FF [FF 00 01]<br>
-     *   -65536                  -> FF FF FF FF FF [FF 00 00]<br>
-     *   -65537                  -> FF FF FF FF FF [FE FF FF]<br>
-     *   -8388607                -> FF FF FF FF FF [80 00 01]<br>
-     *   -8388608                -> FF FF FF FF FF [80 00 00]<br>
-     *   -8388609                -> FF FF FF FF [FF 7F FF FF]<br>
-     *   -16777215               -> FF FF FF FF [FF 00 00 01]<br>
-     *   -16777216               -> FF FF FF FF [FF 00 00 00]<br>
-     *   -16777217               -> FF FF FF FF [FE FF FF FF]<br>
-     *   -2147483647             -> FF FF FF FF [80 00 00 01]<br>
-     *   -2147483648             -> FF FF FF FF [80 00 00 00]<br>
-     *   -2147483649             -> FF FF FF [FF 7F FF FF FF]<br>
-     *   -4294967295             -> FF FF FF [FF 00 00 00 01]<br>
-     *   -4294967296             -> FF FF FF [FF 00 00 00 00]<br>
-     *   -4294967297             -> FF FF FF [FE FF FF FF FF]<br>
-     *   -549755813887           -> FF FF FF [80 00 00 00 01]<br>
-     *   -549755813888           -> FF FF FF [80 00 00 00 00]<br>
-     *   -549755813889           -> FF FF [FF 7F FF FF FF FF]<br>
-     *   -1099511627775          -> FF FF [FF 00 00 00 00 01]<br>
-     *   -1099511627776          -> FF FF [FF 00 00 00 00 00]<br>
-     *   -1099511627777          -> FF FF [FE FF FF FF FF FF]<br>
-     *   -140737488355327        -> FF FF [80 00 00 00 00 01]<br>
-     *   -140737488355328        -> FF FF [80 00 00 00 00 00]<br>
-     *   -140737488355329        -> FF [FF 7F FF FF FF FF FF]<br>
-     *   -281474976710655        -> FF [FF 00 00 00 00 00 01]<br>
-     *   -281474976710656        -> FF [FF 00 00 00 00 00 00]<br>
-     *   -281474976710657        -> FF [FE FF FF FF FF FF FF]<br>
-     *   -36028797018963967      -> FF [80 00 00 00 00 00 01]<br>
-     *   -36028797018963968      -> FF [80 00 00 00 00 00 00]<br>
-     *   -36028797018963969      -> [FF 7F FF FF FF FF FF FF]<br>
-     *   -72057594037927935      -> [FF 00 00 00 00 00 00 01]<br>
-     *   -72057594037927936      -> [FF 00 00 00 00 00 00 00]<br>
-     *   -72057594037927937      -> [FE FF FF FF FF FF FF FF]<br>
-     *   -9223372036854775807    -> [80 00 00 00 00 00 00 01]<br>
-     *   -9223372036854775808    -> [80 00 00 00 00 00 00 00]<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.
      */
@@ -628,7 +632,7 @@
 
     /**
      * 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
@@ -663,7 +667,7 @@
 
     /**
      * 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
@@ -680,9 +684,9 @@
         {
             buffer.put( UniversalTag.BIT_STRING.getValue() );
 
-            // The BitString length. We add one byte for the unused number 
+            // The BitString length. We add one byte for the unused number
             // of bits
-            byte[] bytes = bitString.getData(); 
+            byte[] bytes = bitString.getData();
             int length = bytes.length;
 
             buffer.put( TLV.getBytes( length ) );
@@ -697,7 +701,7 @@
 
     /**
      * 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
@@ -733,7 +737,7 @@
 
     /**
      * 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
@@ -765,7 +769,7 @@
 
     /**
      * 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
@@ -793,7 +797,7 @@
 
     /**
      * 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
@@ -821,7 +825,7 @@
 
     /**
      * 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
@@ -850,7 +854,7 @@
 
     /**
      * 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
@@ -878,7 +882,7 @@
 
     /**
      * 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
@@ -911,9 +915,10 @@
 
     /**
      * Return a string representing the Value
-     * 
+     *
      * @return A string representing the value
      */
+    @Override
     public String toString()
     {
         StringBuilder sb = new StringBuilder();
diff --git a/dsml-engine/pom.xml b/dsml-engine/pom.xml
index 44f4dac..d129850 100644
--- a/dsml-engine/pom.xml
+++ b/dsml-engine/pom.xml
@@ -37,11 +37,6 @@
     
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>shared-ldap</artifactId>
-    </dependency>
-    
-    <dependency>
-      <groupId>${project.groupId}</groupId>
       <artifactId>shared-dsml-parser</artifactId>
     </dependency>
     
diff --git a/dsml-engine/src/main/java/org/apache/directory/shared/dsmlv2/engine/Dsmlv2Engine.java b/dsml-engine/src/main/java/org/apache/directory/shared/dsmlv2/engine/Dsmlv2Engine.java
index e236654..3ae99d6 100644
--- a/dsml-engine/src/main/java/org/apache/directory/shared/dsmlv2/engine/Dsmlv2Engine.java
+++ b/dsml-engine/src/main/java/org/apache/directory/shared/dsmlv2/engine/Dsmlv2Engine.java
@@ -50,8 +50,8 @@
 import org.apache.directory.shared.dsmlv2.request.BatchRequestDsml.Processing;
 import org.apache.directory.shared.dsmlv2.request.BatchRequestDsml.ResponseOrder;
 import org.apache.directory.shared.i18n.I18n;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.api.LdapCodecServiceFactory;
 import org.apache.directory.shared.ldap.model.cursor.Cursor;
 import org.apache.directory.shared.ldap.model.exception.LdapException;
 import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
@@ -115,7 +115,7 @@
     /** The batch response. */
     private BatchResponseDsml batchResponse;
     
-    private LdapCodecService codec = new DefaultLdapCodecService();
+    private LdapCodecService codec = LdapCodecServiceFactory.getSingleton();
 
     private Dsmlv2Grammar grammar = new Dsmlv2Grammar( codec );
 
diff --git a/dsml-parser/pom.xml b/dsml-parser/pom.xml
index 73cba5b..115ec74 100644
--- a/dsml-parser/pom.xml
+++ b/dsml-parser/pom.xml
@@ -38,12 +38,18 @@
 
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>shared-i18n</artifactId>
+      <artifactId>shared-ldap-codec-standalone</artifactId>
+      <scope>test</scope>
     </dependency>
     
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>shared-ldap</artifactId>
+      <artifactId>shared-ldap-codec</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-model</artifactId>
     </dependency>
     
     <dependency>
@@ -65,6 +71,24 @@
   <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>
+              ${project.build.directory}/osgi-cache
+            </org.osgi.framework.storage>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <configuration>
diff --git a/dsml-parser/src/test/java/org/apache/directory/shared/dsmlv2/AbstractTest.java b/dsml-parser/src/test/java/org/apache/directory/shared/dsmlv2/AbstractTest.java
index b5b9230..4772764 100644
--- a/dsml-parser/src/test/java/org/apache/directory/shared/dsmlv2/AbstractTest.java
+++ b/dsml-parser/src/test/java/org/apache/directory/shared/dsmlv2/AbstractTest.java
@@ -25,8 +25,8 @@
 import static org.junit.Assert.fail;
 
 import org.apache.directory.shared.dsmlv2.request.Dsmlv2Grammar;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.api.LdapCodecServiceFactory;
 import org.xmlpull.v1.XmlPullParserException;
 
 /**
@@ -37,7 +37,7 @@
 public abstract class AbstractTest
 {
     /** The LDAP encoder decoder service */
-    private LdapCodecService codec = new DefaultLdapCodecService();
+    private LdapCodecService codec = LdapCodecServiceFactory.getSingleton();
     
     private Dsmlv2Grammar grammar = new Dsmlv2Grammar( codec );
     
diff --git a/integ/pom.xml b/integ/pom.xml
index b461ec3..95253b0 100644
--- a/integ/pom.xml
+++ b/integ/pom.xml
@@ -41,7 +41,6 @@
      integration tests.
    -->
   
-
   <description>
     A place to put integration tests that if put in their rightful
     project position would incure some cyclic dependencies even if
@@ -62,13 +61,47 @@
     </dependency>
 
     <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-extras-codec</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-codec-standalone</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
       <version>${commons.io.version}</version>
       <scope>test</scope>
     </dependency>
+
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam-junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam-container-default</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
+  <properties>
+    <codec.plugin.directory>${project.build.directory}/pluginDirectory</codec.plugin.directory>
+  </properties>
+
   <build>
     <plugins>
       <plugin>
@@ -77,9 +110,49 @@
         <configuration>
           <systemPropertyVariables>
             <workingDirectory>${basedir}/target</workingDirectory>
+            <felix.cache.rootdir>
+              ${project.build.directory}
+            </felix.cache.rootdir>
+            <felix.cache.locking>
+              true
+            </felix.cache.locking>
+            <org.osgi.framework.storage.clean>
+              onFirstInit
+            </org.osgi.framework.storage.clean>
+            <org.osgi.framework.storage>
+              osgi-cache
+            </org.osgi.framework.storage>
+            <codec.plugin.directory>
+              ${codec.plugin.directory}
+            </codec.plugin.directory>
           </systemPropertyVariables>
         </configuration>
       </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>copy</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>${project.groupId}</groupId>
+                  <artifactId>shared-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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedOpFactory.java b/integ/src/test/java/org/apache/directory/shared/ldap/codec/api/DefaultLdapCodecServiceTest.java
similarity index 69%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedOpFactory.java
rename to integ/src/test/java/org/apache/directory/shared/ldap/codec/api/DefaultLdapCodecServiceTest.java
index 6295ba6..6788bad 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedOpFactory.java
+++ b/integ/src/test/java/org/apache/directory/shared/ldap/codec/api/DefaultLdapCodecServiceTest.java
@@ -20,23 +20,21 @@
 package org.apache.directory.shared.ldap.codec.api;
 
 
-import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
-import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
+import org.junit.Test;
 
 
 /**
- * The LdapCodec interface, defined by the codec API.
+ * Tests for StandaloneLdapCodecService.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$, $Date$
  */
-public interface ExtendedOpFactory<Q extends ExtendedRequest, P extends ExtendedResponse>
+public class DefaultLdapCodecServiceTest
 {
-    String getResponseOid();
-    
-    String getRequestOid();
-    
-    Q newRequest();
-    
-    P newResponse();
+    /**
+     * In situ OSGi test run.
+     */
+    @Test
+    public void testLoadingExtras()
+    {
+    }
 }
diff --git a/integ/src/test/java/org/apache/directory/shared/ldap/codec/api/StandaloneLdapCodecServiceTest.java b/integ/src/test/java/org/apache/directory/shared/ldap/codec/api/StandaloneLdapCodecServiceTest.java
new file mode 100644
index 0000000..77cafd0
--- /dev/null
+++ b/integ/src/test/java/org/apache/directory/shared/ldap/codec/api/StandaloneLdapCodecServiceTest.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.shared.ldap.codec.api;
+
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.shared.ldap.codec.standalone.StandaloneLdapCodecService;
+import org.apache.directory.shared.ldap.extras.controls.PasswordPolicy;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.junit.Test;
+
+
+/**
+ * Tests for StandaloneLdapCodecService.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StandaloneLdapCodecServiceTest
+{   
+    /**
+     * Test method for {@link org.apache.directory.shared.ldap.codec.standalone.StandaloneLdapCodecService#StandaloneLdapCodecService()}.
+     */
+    @Test
+    public void testLoadingExtras()
+    {
+        StandaloneLdapCodecService codec = new StandaloneLdapCodecService();
+        
+        assertTrue( codec.isControlRegistered( PasswordPolicy.OID ) );
+
+        CodecControl<? extends Control> control = codec.newControl( PasswordPolicy.OID );
+        assertNotNull( control );
+        System.out.println( control );
+        assertNotNull( codec );
+        codec.shutdown();
+    }
+}
diff --git a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/entry/EntryTest.java b/integ/src/test/java/org/apache/directory/shared/ldap/entry/EntryTest.java
similarity index 96%
rename from ldap-model/src/test/java/org/apache/directory/shared/ldap/model/entry/EntryTest.java
rename to integ/src/test/java/org/apache/directory/shared/ldap/entry/EntryTest.java
index bcf97d6..6d0eac6 100644
--- a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/entry/EntryTest.java
+++ b/integ/src/test/java/org/apache/directory/shared/ldap/entry/EntryTest.java
@@ -16,14 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.directory.shared.ldap.model.entry;
+package org.apache.directory.shared.ldap.entry;
 
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertNotNull;
 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;
@@ -32,25 +32,30 @@
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.util.Arrays;
-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 com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
-import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.entry.BinaryValue;
+import org.apache.directory.shared.ldap.model.entry.DefaultEntry;
+import org.apache.directory.shared.ldap.model.entry.DefaultEntryAttribute;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.model.entry.StringValue;
+import org.apache.directory.shared.ldap.model.entry.Value;
 import org.apache.directory.shared.ldap.model.exception.LdapException;
 import org.apache.directory.shared.ldap.model.name.Dn;
-import org.apache.directory.shared.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
-import org.apache.directory.shared.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+import org.apache.directory.shared.ldap.schemamanager.impl.DefaultSchemaManager;
 import org.apache.directory.shared.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
  * 
@@ -64,8 +69,8 @@
     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 Map<String, OidNormalizer> oids;
     
+    private static SchemaManager schemaManager;
     
     /**
      * Helper method which creates an entry with 4 attributes.
@@ -174,24 +179,7 @@
     public static void setUpBeforeClass() throws Exception
     {
         EXAMPLE_DN = new Dn( "dc=example,dc=com" );
-
-        oids = new HashMap<String, OidNormalizer>();
-
-        // 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 );
+        schemaManager = new DefaultSchemaManager();
     }
 
 
@@ -1271,7 +1259,7 @@
     {
         Dn dn = new Dn( "ou=system" );
         
-        dn.normalize( oids );
+        dn.normalize( schemaManager );
         
         byte[] password = Strings.getBytesUtf8("secret");
         Entry entry = new DefaultEntry( dn);
@@ -1325,7 +1313,7 @@
     {
         Dn dn = new Dn( "ou=system" );
         
-        dn.normalize( oids );
+        dn.normalize( schemaManager );
         
         Entry entry = new DefaultEntry( dn );
 
diff --git a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnTest.java b/integ/src/test/java/org/apache/directory/shared/ldap/name/DnTest.java
similarity index 76%
rename from ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnTest.java
rename to integ/src/test/java/org/apache/directory/shared/ldap/name/DnTest.java
index 83e10a1..bdc2e07 100644
--- a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnTest.java
+++ b/integ/src/test/java/org/apache/directory/shared/ldap/name/DnTest.java
@@ -17,7 +17,7 @@
  *  under the License.
  *
  */
-package org.apache.directory.shared.ldap.model.name;
+package org.apache.directory.shared.ldap.name;
 
 
 import static junit.framework.Assert.assertNotNull;
@@ -31,30 +31,31 @@
 
 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.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.ldap.model.exception.LdapException;
-import org.apache.directory.shared.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
-import org.apache.directory.shared.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.name.Ava;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.name.DnParser;
+import org.apache.directory.shared.ldap.model.name.DnSerializer;
+import org.apache.directory.shared.ldap.model.name.Rdn;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+import org.apache.directory.shared.ldap.schemamanager.impl.DefaultSchemaManager;
 import org.apache.directory.shared.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
@@ -65,41 +66,18 @@
 @Concurrency()
 public class DnTest
 {
-    private static Map<String, OidNormalizer> oids;
-    private static Map<String, OidNormalizer> oidOids;
-
+    private static SchemaManager schemaManager;
 
     /**
      * Initialize OIDs maps for normalization
      */
     @BeforeClass
-    public static void initMapOids()
+    public static void setup() throws Exception
     {
-        oids = new HashMap<String, OidNormalizer>();
-
-        oids.put( "dc", new OidNormalizer( "dc", new DeepTrimToLowerNormalizer() ) );
-        oids.put( "domaincomponent", new OidNormalizer( "dc", new DeepTrimToLowerNormalizer() ) );
-        oids.put( "0.9.2342.19200300.100.1.25", new OidNormalizer( "dc", new DeepTrimToLowerNormalizer() ) );
-
-        oids.put( "ou", new OidNormalizer( "ou", new DeepTrimToLowerNormalizer() ) );
-        oids.put( "organizationalUnitName", new OidNormalizer( "ou", new DeepTrimToLowerNormalizer() ) );
-        oids.put( "2.5.4.11", new OidNormalizer( "ou", new DeepTrimToLowerNormalizer() ) );
-
-        // Another map where we store OIDs instead of names.
-        oidOids = new HashMap<String, OidNormalizer>();
-
-        oidOids.put( "dc", new OidNormalizer( "0.9.2342.19200300.100.1.25", new DeepTrimToLowerNormalizer() ) );
-        oidOids.put( "domaincomponent", new OidNormalizer( "0.9.2342.19200300.100.1.25",
-            new DeepTrimToLowerNormalizer() ) );
-        oidOids.put( "0.9.2342.19200300.100.1.25", new OidNormalizer( "0.9.2342.19200300.100.1.25",
-            new DeepTrimToLowerNormalizer() ) );
-        oidOids.put( "ou", new OidNormalizer( "2.5.4.11", new DeepTrimToLowerNormalizer() ) );
-        oidOids.put( "organizationalUnitName", new OidNormalizer( "2.5.4.11", new DeepTrimToLowerNormalizer() ) );
-        oidOids.put( "2.5.4.11", new OidNormalizer( "2.5.4.11", new DeepTrimToLowerNormalizer() ) );
+        schemaManager = new DefaultSchemaManager();
     }
 
 
-    // ~ Methods
     // ------------------------------------------------------------------------------------
     // CONSTRUCTOR functions --------------------------------------------------
 
@@ -418,7 +396,7 @@
         assertEquals( "ou = \\#this is a sharp", dn.getName() );
 
         // Check the normalization now
-        Dn ndn = dn.normalize( oidOids );
+        Dn ndn = dn.normalize( schemaManager );
 
         assertEquals( "ou = \\#this is a sharp", ndn.getName() );
         assertEquals( "2.5.4.11=\\#this is a sharp", ndn.getNormName() );
@@ -438,7 +416,7 @@
         assertEquals( "ou = AC\\\\DC", dn.getName() );
 
         // Check the normalization now
-        Dn ndn = dn.normalize( oidOids );
+        Dn ndn = dn.normalize( schemaManager );
         assertEquals( "ou = AC\\\\DC", ndn.getName() );
         assertEquals( "2.5.4.11=ac\\\\dc", ndn.getNormName() );
     }
@@ -536,7 +514,7 @@
 
     /**
      * test a remove from position 0
-     */
+     *
     @Test
     public void testDnRemove0() throws LdapException
     {
@@ -552,7 +530,7 @@
 
     /**
      * test a remove from position 1
-     */
+     *
     @Test
     public void testDnRemove1() throws LdapException
     {
@@ -565,7 +543,7 @@
 
     /**
      * test a remove from position 2
-     */
+     *
     @Test
     public void testDnRemove2() throws LdapException
     {
@@ -579,7 +557,7 @@
 
     /**
      * test a remove from position 1 whith semi colon
-     */
+     *
     @Test
     public void testDnRemove1WithSemiColon() throws LdapException
     {
@@ -593,7 +571,7 @@
 
     /**
      * test a remove out of bound
-     */
+     *
     @Test
     public void testDnRemoveOutOfBound() throws LdapException
     {
@@ -682,10 +660,10 @@
         dn = dn.add( "c = d" );
         assertEquals( 2, dn.size() );
 
-        dn = dn.remove( 0 );
+        dn = dn.getParent();
         assertEquals( 1, dn.size() );
 
-        dn = dn.remove( 0 );
+        dn = dn.getParent();
         assertEquals( 0, dn.size() );
     }
 
@@ -747,40 +725,12 @@
     {
         Dn dn = new Dn( "a=b, c=d" );
 
-        dn = dn.add( dn.size(), "e = f" );
+        dn = dn.add( "e = f" );
         assertEquals( "e = f,a=b, c=d", dn.getName() );
         assertEquals( 3, dn.size() );
     }
 
 
-    /**
-     * test Add at the start of an existing Dn
-     */
-    @Test
-    public void testDnAddStart() throws LdapException
-    {
-        Dn dn = new Dn( "a=b, c=d" );
-
-        dn = dn.add( 0, "e = f" );
-        assertEquals( "a=b, c=d,e = f", dn.getName() );
-        assertEquals( 3, dn.size() );
-    }
-
-
-    /**
-     * test Add at the middle of an existing Dn
-     */
-    @Test
-    public void testDnAddMiddle() throws LdapException
-    {
-        Dn dn = new Dn( "a=b, c=d" );
-
-        dn = dn.add( 1, "e = f" );
-        assertEquals( "a=b,e = f, c=d", dn.getName() );
-        assertEquals( 3, dn.size() );
-    }
-
-
     // ADD ALL Operations
     /**
      * Test AddAll
@@ -912,8 +862,8 @@
     public void testDnGetPrefixPos0() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        Dn newDn = ( dn.getPrefix( 0 ) );
-        assertEquals( "", newDn.getName() );
+        Dn newDn = ( dn.getAncestorOf( "" ) );
+        assertEquals( "a=b, c=d,e = f", newDn.getName() );
     }
 
 
@@ -924,8 +874,8 @@
     public void testDnGetPrefixPos1() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        Dn newDn = ( dn.getPrefix( 1 ) );
-        assertEquals( "e = f", newDn.getName() );
+        Dn newDn = ( dn.getAncestorOf( "a=b" ) );
+        assertEquals( " c=d,e = f", newDn.getName() );
     }
 
 
@@ -936,8 +886,8 @@
     public void testDnGetPrefixPos2() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        Dn newDn = ( dn.getPrefix( 2 ) );
-        assertEquals( " c=d,e = f", newDn.getName() );
+        Dn newDn = ( dn.getAncestorOf( "a=b, c=d" ) );
+        assertEquals( "e = f", newDn.getName() );
     }
 
 
@@ -948,29 +898,20 @@
     public void testDnGetPrefixPos3() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        Dn newDn = ( dn.getPrefix( 3 ) );
-        assertEquals( "a=b, c=d,e = f", newDn.getName() );
+        Dn newDn = ( dn.getAncestorOf( "a=b, c=d,e = f" ) );
+        assertEquals( "", newDn.getName() );
     }
 
 
     /**
      * Get the prefix out of bound
      */
-    @Test
+    @Test( expected=LdapInvalidDnException.class)
     public void testDnGetPrefixPos4() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
 
-        try
-        {
-            dn.getPrefix( 4 );
-            // We should not reach this point.
-            fail();
-        }
-        catch ( ArrayIndexOutOfBoundsException aoobe )
-        {
-            assertTrue( true );
-        }
+        Dn res = dn.getAncestorOf( "a=z" );
     }
 
 
@@ -978,10 +919,10 @@
      * Get the prefix of an empty LdapName
      */
     @Test
-    public void testDnGetPrefixEmptyDN()
+    public void testDnGetPrefixEmptyDN() throws LdapInvalidDnException
     {
         Dn dn = new Dn();
-        Dn newDn = ( dn.getPrefix( 0 ) );
+        Dn newDn = ( dn.getAncestorOf( "" ) );
         assertEquals( "", newDn.getName() );
     }
 
@@ -1093,7 +1034,7 @@
 
     /**
      * Test that a Dn is empty
-     */
+     *
     @Test
     public void testDnRemoveIsEmpty() throws LdapException
     {
@@ -1116,7 +1057,7 @@
     public void testDnStartsWithNull() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.isChildOf( (Dn) null ) );
+        assertEquals( true, dn.isDescendantOf( (Dn) null ) );
     }
 
 
@@ -1127,7 +1068,7 @@
     public void testDnStartsWithEmpty() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.isChildOf( new Dn() ) );
+        assertEquals( true, dn.isDescendantOf( new Dn() ) );
     }
 
 
@@ -1138,7 +1079,7 @@
     public void testDnStartsWithSimple() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.isChildOf( new Dn( "e=f" ) ) );
+        assertEquals( true, dn.isDescendantOf( new Dn( "e=f" ) ) );
     }
 
 
@@ -1149,7 +1090,7 @@
     public void testDnStartsWithComplex() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.isChildOf( new Dn( "c =  d, e =  f" ) ) );
+        assertEquals( true, dn.isDescendantOf( new Dn( "c =  d, e =  f" ) ) );
     }
 
 
@@ -1160,7 +1101,7 @@
     public void testDnStartsWithComplexMixedCase() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( false, dn.isChildOf( new Dn( "c =  D, E =  f" ) ) );
+        assertEquals( false, dn.isDescendantOf( new Dn( "c =  D, E =  f" ) ) );
     }
 
 
@@ -1171,7 +1112,7 @@
     public void testDnStartsWithFull() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.isChildOf( new Dn( "a=  b; c =  d, e =  f" ) ) );
+        assertEquals( true, dn.isDescendantOf( new Dn( "a=  b; c =  d, e =  f" ) ) );
     }
 
 
@@ -1182,7 +1123,7 @@
     public void testDnStartsWithWrong() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( false, dn.isChildOf( new Dn( "c =  t, e =  f" ) ) );
+        assertEquals( false, dn.isDescendantOf( new Dn( "c =  t, e =  f" ) ) );
     }
 
 
@@ -1194,298 +1135,10 @@
     public void testDnEndsWithNull() throws LdapException
     {
         Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.hasSuffix( (Dn) null ) );
+        assertEquals( true, dn.isDescendantOf( (Dn) null ) );
     }
 
 
-    /**
-     * Test a endsWith an empty Dn
-     */
-    @Test
-    public void testDnEndsWithEmpty() throws LdapException
-    {
-        Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.hasSuffix( new Dn() ) );
-    }
-
-
-    /**
-     * Test a endsWith an simple Dn
-     */
-    @Test
-    public void testDnEndsWithSimple() throws LdapException
-    {
-        Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.hasSuffix( new Dn( "a=b" ) ) );
-    }
-
-
-    /**
-     * Test a endsWith a complex Dn
-     */
-    @Test
-    public void testDnEndsWithComplex() throws LdapException
-    {
-        Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.hasSuffix( new Dn( "a =  b, c =  d" ) ) );
-    }
-
-
-    /**
-     * Test a endsWith a complex Dn
-     */
-    @Test
-    public void testDnEndsWithComplexMixedCase() throws LdapException
-    {
-        Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( false, dn.hasSuffix( new Dn( "a =  B, C =  d" ) ) );
-    }
-
-
-    /**
-     * Test a endsWith a full Dn
-     */
-    @Test
-    public void testDnEndsWithFull() throws LdapException
-    {
-        Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( true, dn.hasSuffix( new Dn( "a=  b; c =  d, e =  f" ) ) );
-    }
-
-
-    /**
-     * Test a endsWith which returns false
-     */
-    @Test
-    public void testDnEndsWithWrong() throws LdapException
-    {
-        Dn dn = new Dn( "a=b, c=d,e = f" );
-        assertEquals( false, dn.hasSuffix( new Dn( "a =  b, e =  f" ) ) );
-    }
-
-
-    // GET ALL operations
-    /**
-     * test a getAll operation on a null Dn
-     *
-    @Test
-    public void testDnGetAllNull()
-    {
-        Dn dn = new Dn();
-        Enumeration<String> nc = dn.getAll();
-
-        assertEquals( false, nc.hasMoreElements() );
-    }
-
-
-    /**
-     * test a getAll operation on an empty Dn
-     *
-    @Test
-    public void testDnGetAllEmpty() throws LdapException
-    {
-        Dn dn = new Dn( "" );
-        Enumeration<String> nc = dn.getAll();
-
-        assertEquals( false, nc.hasMoreElements() );
-    }
-
-
-    /**
-     * test a getAll operation on a simple Dn
-     *
-    @Test
-    public void testDnGetAllSimple() throws LdapException
-    {
-        Dn dn = new Dn( "a=b" );
-        Enumeration<String> nc = dn.getAll();
-
-        assertEquals( true, nc.hasMoreElements() );
-        assertEquals( "a=b", nc.nextElement() );
-        assertEquals( false, nc.hasMoreElements() );
-    }
-
-
-    /**
-     * test a getAll operation on a complex Dn
-     *
-    @Test
-    public void testDnGetAllComplex() throws LdapException
-    {
-        Dn dn = new Dn( "e=f+g=h,a=b,c=d" );
-        Enumeration<String> nc = dn.getAll();
-
-        assertEquals( true, nc.hasMoreElements() );
-        assertEquals( "c=d", nc.nextElement() );
-        assertEquals( true, nc.hasMoreElements() );
-        assertEquals( "a=b", nc.nextElement() );
-        assertEquals( true, nc.hasMoreElements() );
-        assertEquals( "e=f+g=h", nc.nextElement() );
-        assertEquals( false, nc.hasMoreElements() );
-    }
-
-
-    /**
-     * test a getAll operation on a complex Dn
-     *
-    @Test
-    public void testDnGetAllComplexOrdered() throws LdapException
-    {
-        Dn dn = new Dn( "g=h+e=f,a=b,c=d" );
-        Enumeration<String> nc = dn.getAll();
-
-        assertEquals( true, nc.hasMoreElements() );
-        assertEquals( "c=d", nc.nextElement() );
-        assertEquals( true, nc.hasMoreElements() );
-        assertEquals( "a=b", nc.nextElement() );
-        assertEquals( true, nc.hasMoreElements() );
-
-        assertEquals( "e=f+g=h", nc.nextElement() );
-        assertEquals( false, nc.hasMoreElements() );
-    }
-
-
-    // CLONE Operation
-    /**
-     * test a clone operation on a empty Dn
-     */
-    @Test
-    public void testDnCloneEmpty()
-    {
-        Dn dn = new Dn();
-        Dn clone = (Dn) dn.clone();
-
-        assertEquals( "", clone.getName() );
-    }
-
-
-    /**
-     * test a clone operation on a simple Dn
-     */
-    @Test
-    public void testDnCloneSimple() throws LdapException
-    {
-        Dn dn = new Dn( "a=b" );
-        Dn clone = (Dn) dn.clone();
-
-        assertEquals( "a=b", clone.getName() );
-        dn.remove( 0 );
-        assertEquals( "a=b", clone.getName() );
-    }
-
-
-    /**
-     * test a clone operation on a complex Dn
-     */
-    @Test
-    public void testDnCloneComplex() throws LdapException
-    {
-        Dn dn = new Dn( "e=f+g=h,a=b,c=d" );
-        Dn clone = (Dn) dn.clone();
-
-        assertEquals( "e=f+g=h,a=b,c=d", clone.getName() );
-        dn.remove( 2 );
-        assertEquals( "e=f+g=h,a=b,c=d", clone.getName() );
-    }
-
-
-    // GET operations
-    /**
-     * test a get in a null Dn
-     */
-    @Test
-    public void testDnGetNull()
-    {
-        Dn dn = new Dn();
-        assertEquals( "", dn.get( 0 ) );
-    }
-
-
-    /**
-     * test a get in an empty Dn
-     */
-    @Test
-    public void testDnGetEmpty() throws LdapException
-    {
-        Dn dn = new Dn( "" );
-        assertEquals( "", dn.get( 0 ) );
-    }
-
-
-    /**
-     * test a get in a simple Dn
-     */
-    @Test
-    public void testDnGetSimple() throws LdapException
-    {
-        Dn dn = new Dn( "a = b" );
-        assertEquals( "a=b", dn.get( 0 ) );
-    }
-
-
-    /**
-     * test a get in a complex Dn
-     */
-    @Test
-    public void testDnGetComplex() throws LdapException
-    {
-        Dn dn = new Dn( "a = b + c= d, e= f; g =h" );
-        assertEquals( "g=h", dn.get( 0 ) );
-        assertEquals( "e=f", dn.get( 1 ) );
-        assertEquals( "a=b+c=d", dn.get( 2 ) );
-    }
-
-
-    /**
-     * test a get out of bound
-     */
-    @Test
-    public void testDnGetOutOfBound() throws LdapException
-    {
-        Dn dn = new Dn( "a = b + c= d, e= f; g =h" );
-
-        try
-        {
-            dn.get( 4 );
-            fail();
-        }
-        catch ( IndexOutOfBoundsException aioob )
-        {
-            assertTrue( true );
-        }
-    }
-
-
-    /**
-     * Tests the examples from the JNDI tutorials to make sure LdapName behaves
-     * appropriately. The example can be found online <a href="">here</a>.
-     *
-     * @throws Exception
-     *             if anything goes wrong
-     */
-    @Test
-    public void testJNDITutorialExample() throws Exception
-    {
-        // Parse the name
-        Dn name = new Dn( "cn=John,ou=People,ou=Marketing" );
-
-        // Remove the second component from the head: ou=People
-        name = name.remove( 1 );
-        String out = name.toString();
-
-        assertEquals( "cn=John,ou=Marketing", out );
-
-        // Add to the head (first): cn=John,ou=Marketing,ou=East
-        name = name.add( 0, "ou=East" );
-        out = name.toString();
-
-        assertEquals( "cn=John,ou=Marketing,ou=East", out );
-
-        // Add to the tail (last): cn=HomeDir,cn=John,ou=Marketing,ou=East
-        out = name.add( "cn=HomeDir" ).toString();
-
-        assertEquals( "cn=HomeDir,cn=John,ou=Marketing,ou=East", out );
-    }
 
 
     @Test
@@ -1519,13 +1172,14 @@
     }
 
 
+    
     @Test
     public void testAttributeComparisonIsCaseInSensitive() throws Exception
     {
         Dn name1 = new Dn( "cn=HomeDir" );
         Dn name2 = new Dn( "CN=HomeDir" );
 
-        assertEquals( 0, name1.compareTo( name2 ) );
+        assertEquals( name1, name2 );
     }
 
 
@@ -1535,7 +1189,7 @@
         Dn name1 = new Dn( "cn=HomeDir+cn=WorkDir" );
         Dn name2 = new Dn( "cn=HomeDir+CN=WorkDir" );
 
-        assertEquals( 0, name1.compareTo( name2 ) );
+        assertEquals( name1, name2 );
     }
 
 
@@ -1546,7 +1200,7 @@
         Dn name1 = new Dn( "cn=HomeDir+cn=WorkDir" );
         Dn name2 = new Dn( "cn=WorkDir+cn=HomeDir" );
 
-        assertEquals( 0, name1.compareTo( name2 ) );
+        assertEquals( name1, name2 );
     }
 
 
@@ -1557,7 +1211,7 @@
         Dn name1 = new Dn( "cn= HomeDir+cn=Workdir" );
         Dn name2 = new Dn( "cn = Work+cn=HomeDir" );
 
-        assertEquals( 1, name1.compareTo( name2 ) );
+        assertNotSame( name1, name2 );
     }
 
 
@@ -1611,18 +1265,18 @@
         Dn name4 = new Dn( "cn=Website,cn=John,ou=Marketing,ou=West" );
         Dn name5 = new Dn( "cn=Airline,cn=John,ou=Marketing,ou=West" );
 
-        assertTrue( name0.compareTo( copy ) == 0 );
-        assertTrue( name0.compareTo( name1 ) < 0 );
-        assertTrue( name0.compareTo( name2 ) < 0 );
-        assertTrue( name1.compareTo( name2 ) < 0 );
-        assertTrue( name2.compareTo( name1 ) > 0 );
-        assertTrue( name2.compareTo( name0 ) > 0 );
-        assertTrue( name2.compareTo( name3 ) < 0 );
-        assertTrue( name2.compareTo( name4 ) < 0 );
-        assertTrue( name3.compareTo( name4 ) < 0 );
-        assertTrue( name3.compareTo( name5 ) > 0 );
-        assertTrue( name4.compareTo( name5 ) > 0 );
-        assertTrue( name2.compareTo( name5 ) < 0 );
+        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 );
     }
 
 
@@ -1642,7 +1296,7 @@
      *
      * @throws Exception
      *             if anything goes wrong.
-     */
+     *
     @Test
     public void testClone() throws Exception
     {
@@ -1653,81 +1307,6 @@
 
 
     /**
-     * Class to test for compareTo
-     *
-     * @throws Exception
-     *             if anything goes wrong.
-     */
-    @Test
-    public void testCompareTo() throws Exception
-    {
-        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" );
-
-        assertTrue( name0.compareTo( copy ) == 0 );
-        assertTrue( name0.compareTo( name1 ) < 0 );
-        assertTrue( name0.compareTo( name2 ) < 0 );
-        assertTrue( name1.compareTo( name2 ) < 0 );
-        assertTrue( name2.compareTo( name1 ) > 0 );
-        assertTrue( name2.compareTo( name0 ) > 0 );
-        assertTrue( name2.compareTo( name3 ) < 0 );
-        assertTrue( name2.compareTo( name4 ) < 0 );
-        assertTrue( name3.compareTo( name4 ) < 0 );
-        assertTrue( name3.compareTo( name5 ) > 0 );
-        assertTrue( name4.compareTo( name5 ) > 0 );
-        assertTrue( name2.compareTo( name5 ) < 0 );
-
-        List<Dn> list = new ArrayList<Dn>();
-
-        Comparator<Dn> comparator = new Comparator<Dn>()
-        {
-            public int compare( Dn obj1, Dn obj2 )
-            {
-                Dn n1 = obj1;
-                Dn n2 = obj2;
-                return n1.compareTo( n2 );
-            }
-
-
-            public boolean equals( Object obj )
-            {
-                return super.equals( obj );
-            }
-
-
-            /**
-             * Compute the instance's hash code
-             * @return the instance's hash code
-             */
-            public int hashCode()
-            {
-                return super.hashCode();
-            }
-        };
-
-        list.add( name0 );
-        list.add( name1 );
-        list.add( name2 );
-        list.add( name3 );
-        list.add( name4 );
-        list.add( name5 );
-        Collections.sort( list, comparator );
-
-        assertEquals( name0, list.get( 0 ) );
-        assertEquals( name1, list.get( 1 ) );
-        assertEquals( name2, list.get( 2 ) );
-        assertEquals( name5, list.get( 3 ) );
-        assertEquals( name3, list.get( 4 ) );
-        assertEquals( name4, list.get( 5 ) );
-    }
-
-
-    /**
      * Class to test for size
      *
      * @throws Exception
@@ -1979,20 +1558,6 @@
 
 
     /**
-     * Test the get( int ) method
-     */
-    @Test
-    public void testGet() throws Exception
-    {
-        Dn name = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
-        assertEquals( "cn=HomeDir", name.get( 3 ) );
-        assertEquals( "cn=John", name.get( 2 ) );
-        assertEquals( "ou=Marketing", name.get( 1 ) );
-        assertEquals( "ou=East", name.get( 0 ) );
-    }
-
-
-    /**
      * Test the getRdn( int ) method
      */
     @Test
@@ -2056,11 +1621,11 @@
     {
         Dn name = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
 
-        assertEquals( "cn=HomeDir,cn=John,ou=Marketing,ou=East", name.getPrefix( 4 ).toString() );
-        assertEquals( "cn=John,ou=Marketing,ou=East", name.getPrefix( 3 ).toString() );
-        assertEquals( "ou=Marketing,ou=East", name.getPrefix( 2 ).toString() );
-        assertEquals( "ou=East", name.getPrefix( 1 ).toString() );
-        assertEquals( "", name.getPrefix( 0 ).toString() );
+        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() );
     }
 
 
@@ -2085,75 +1650,43 @@
         Dn n8 = new Dn( "cn=HomeDir,cn=John,ou=Marketing" );
 
         // Check with Dn
-        assertTrue( n0.isChildOf( n1 ) );
-        assertTrue( n0.isChildOf( n2 ) );
-        assertTrue( n0.isChildOf( n3 ) );
-        assertTrue( n0.isChildOf( n4 ) );
-        assertTrue( n0.isChildOf( n5 ) );
+        assertTrue( n0.isDescendantOf( n1 ) );
+        assertTrue( n0.isDescendantOf( n2 ) );
+        assertTrue( n0.isDescendantOf( n3 ) );
+        assertTrue( n0.isDescendantOf( n4 ) );
+        assertTrue( n0.isDescendantOf( n5 ) );
 
-        assertTrue( !n0.isChildOf( n6 ) );
-        assertTrue( !n0.isChildOf( n7 ) );
-        assertTrue( !n0.isChildOf( n8 ) );
+        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.isChildOf( nn0 ) );
-        assertTrue( nn10.isChildOf( nn0 ) );
-        assertTrue( nn210.isChildOf( nn0 ) );
-        assertTrue( nn3210.isChildOf( nn0 ) );
+        assertTrue( nn0.isDescendantOf( nn0 ) );
+        assertTrue( nn10.isDescendantOf( nn0 ) );
+        assertTrue( nn210.isDescendantOf( nn0 ) );
+        assertTrue( nn3210.isDescendantOf( nn0 ) );
 
-        assertTrue( nn10.isChildOf( nn10 ) );
-        assertTrue( nn210.isChildOf( nn10 ) );
-        assertTrue( nn3210.isChildOf( nn10 ) );
+        assertTrue( nn10.isDescendantOf( nn10 ) );
+        assertTrue( nn210.isDescendantOf( nn10 ) );
+        assertTrue( nn3210.isDescendantOf( nn10 ) );
 
-        assertTrue( nn210.isChildOf( nn210 ) );
-        assertTrue( nn3210.isChildOf( nn210 ) );
+        assertTrue( nn210.isDescendantOf( nn210 ) );
+        assertTrue( nn3210.isDescendantOf( nn210 ) );
 
-        assertTrue( nn3210.isChildOf( nn3210 ) );
+        assertTrue( nn3210.isDescendantOf( nn3210 ) );
 
         assertTrue( "Starting Dn fails with ADS Dn",
-            new Dn( "ou=foo,dc=apache,dc=org" ).isChildOf( new Dn( "dc=apache,dc=org" ) ) );
+            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" ).isChildOf( new Dn( "dc=apache,dc=org" ) ) );
+            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" ).isChildOf( new Dn( "dc=apache,dc=org" ) ) );
-    }
-
-
-    /**
-     * Class to test for endsWith
-     *
-     * @throws Exception
-     *             anything goes wrong
-     */
-    @Test
-    public void testEndsWith() throws Exception
-    {
-        Dn name0 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
-        Dn name1 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
-        Dn name2 = new Dn( "cn=John,ou=Marketing,ou=East" );
-        Dn name3 = new Dn( "ou=Marketing,ou=East" );
-        Dn name4 = new Dn( "ou=East" );
-        Dn name5 = new Dn( "" );
-
-        Dn name6 = new Dn( "cn=HomeDir" );
-        Dn name7 = new Dn( "cn=HomeDir,cn=John" );
-        Dn name8 = new Dn( "cn=HomeDir,cn=John,ou=Marketing" );
-
-        assertTrue( name0.hasSuffix( name1 ) );
-        assertTrue( !name0.hasSuffix( name2 ) );
-        assertTrue( !name0.hasSuffix( name3 ) );
-        assertTrue( !name0.hasSuffix( name4 ) );
-        assertTrue( name0.hasSuffix( name5 ) );
-
-        assertTrue( name0.hasSuffix( name6 ) );
-        assertTrue( name0.hasSuffix( name7 ) );
-        assertTrue( name0.hasSuffix( name8 ) );
+            new Dn( "dc=apache,dc=org" ).isDescendantOf( new Dn( "dc=apache,dc=org" ) ) );
     }
 
 
@@ -2314,74 +1847,23 @@
         assertEquals( name4, name );
 
         Dn name3 = new Dn( "ou=Marketing,ou=East" );
-        name = name.add( 1, "ou=Marketing" );
+        name = name.add( "ou=Marketing" );
         assertEquals( name3, name );
 
         Dn name2 = new Dn( "cn=John,ou=Marketing,ou=East" );
-        name = name.add( 2, "cn=John" );
+        name = name.add( "cn=John" );
         assertEquals( name2, name );
 
         Dn name0 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East" );
-        name = name.add( 3, "cn=HomeDir" );
-        assertEquals( name0, name );
-
-        Dn name5 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East,o=LL " + "Bean Inc." );
-        name = name.add( 0, "o=LL Bean Inc." );
-        assertEquals( name5, name );
-
-        Dn name6 = new Dn( "cn=HomeDir,cn=John,ou=Marketing,ou=East,c=US,o=LL " + "Bean Inc." );
-        name = name.add( 1, "c=US" );
-        assertEquals( name6, name );
-
-        Dn name7 = new Dn( "cn=HomeDir,cn=John,ou=Advertising,ou=Marketing," + "ou=East,c=US,o=LL " + "Bean Inc." );
-        name = name.add( 4, "ou=Advertising" );
-        assertEquals( name7, name );
-    }
-
-
-    /**
-     * Class to test for remove
-     *
-     * @throws Exception
-     *             if anything goes wrong
-     */
-    @Test
-    public void testRemove() throws Exception
-    {
-        Dn name = new Dn();
-        assertEquals( new Dn( "" ), name );
-
-        Dn name3 = new Dn( "ou=Marketing" );
-        name = name.add( "ou=East" );
-        name = name.add( 1, "ou=Marketing" );
-        name = name.remove( 0 );
-        assertEquals( name3, name );
-
-        Dn name2 = new Dn( "cn=HomeDir,ou=Marketing,ou=East" );
-        name = name.add( 0, "ou=East" );
-        name = name.add( 2, "cn=John" );
         name = name.add( "cn=HomeDir" );
-        name = name.remove( 2 );
-        assertEquals( name2, name );
-
-        name = name.remove( 1 );
-        Dn name1 = new Dn( "cn=HomeDir,ou=East" );
-        assertEquals( name1, name );
-
-        name = name.remove( 1 );
-        Dn name0 = new Dn( "ou=East" );
         assertEquals( name0, name );
-
-        name = name.remove( 0 );
-        assertEquals( new Dn( "" ), name );
     }
 
 
     /**
      * Class to test for String toString()
      *
-     * @throws Exception
-     *             if anything goes wrong
+     * @throws Exception if anything goes wrong
      */
     @Test
     public void testToString() throws Exception
@@ -2392,7 +1874,7 @@
         name = name.add( "ou=East" );
         assertEquals( "ou=East", name.toString() );
 
-        name = name.add( 1, "ou=Marketing" );
+        name = name.add( "ou=Marketing" );
         assertEquals( "ou=Marketing,ou=East", name.toString() );
 
         name = name.add( "cn=John" );
@@ -2423,7 +1905,7 @@
         assertEquals( "o=acme", two.getParent().getName() );
 
         Dn three = new Dn( "cn=test,dc=example,dc=com" );
-        three.normalize( oids );
+        three.normalize( schemaManager );
         Dn threeParent = three.getParent();
         assertNotNull( threeParent );
         assertTrue( threeParent.isNormalized() );
@@ -2510,9 +1992,9 @@
 
         assertTrue( name.getName().equals( "ou= Some   People   ,dc = eXample,dc= cOm" ) );
 
-        Dn result = Dn.normalize(name, oids);
+        Dn result = name.normalize( schemaManager );
 
-        assertTrue( ( result ).getNormName().equals( "ou=some people,dc=example,dc=com" ) );
+        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() );
     }
 
 
@@ -2529,7 +2011,7 @@
         assertEquals( "ou", rdn.getNormType() );
         assertEquals( "ou", rdn.getUpType() );
 
-        Dn result = Dn.normalize(name, oidOids);
+        Dn result = name.normalize( 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" ) );
@@ -2551,7 +2033,7 @@
     {
         Dn name = new Dn();
 
-        Dn result = Dn.normalize(name, oids);
+        Dn result = name.normalize( schemaManager );
         assertTrue( result.toString().equals( "" ) );
     }
 
@@ -2565,7 +2047,7 @@
         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 = Dn.normalize(name, oidOids);
+        Dn result = name.normalize( schemaManager );
 
         assertEquals(
             ( result ).getNormName(),
@@ -2586,7 +2068,7 @@
         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 = Dn.normalize(name, oidOids);
+        Dn result = name.normalize( schemaManager);
 
         assertTrue( result
             .getNormName()
@@ -2606,14 +2088,12 @@
     public void testLdapNameHashCode() throws Exception
     {
         Dn name1 = Dn
-            .normalize(
-                    "2.5.4.11= Some   People   + domainComponent=  And   Some anImAls,DomainComponent = eXample,0.9.2342.19200300.100.1.25= cOm",
-                    oids);
+            .normalize( schemaManager,
+                    "2.5.4.11= Some   People   + domainComponent=  And   Some anImAls,DomainComponent = eXample,0.9.2342.19200300.100.1.25= cOm" );
 
         Dn name2 = Dn
-            .normalize(
-                    "2.5.4.11=some people+domainComponent=and some animals,DomainComponent=example,0.9.2342.19200300.100.1.25=com",
-                    oids);
+            .normalize( 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() );
     }
@@ -2642,11 +2122,11 @@
         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.getPrefix( 0 ).toString() );
-        assertEquals( jName.getPrefix( 1 ).toString(), aName.getPrefix( 1 ).toString() );
-        assertEquals( jName.getPrefix( 2 ).toString(), aName.getPrefix( 2 ).toString() );
-        assertEquals( jName.getPrefix( 3 ).toString(), aName.getPrefix( 3 ).toString() );
-        assertEquals( jName.getPrefix( 4 ).toString(), aName.getPrefix( 4 ).toString() );
+        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() );
     }
 
 
@@ -2687,29 +2167,6 @@
      * Test for DIRSERVER-191
      */
     @Test
-    public void testAddIntString() 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( 0, "cn=zero" ) );
-        assertNotSame( aName, aName.add( 0, "cn=zero" ) );
-        assertNotSame( jName.toString(), aName.toString() );
-
-        assertSame( jName, jName.add( 2, "cn=one.5" ) );
-        assertNotSame( aName, aName.add( 2, "cn=one.5" ) );
-        assertNotSame( jName.toString(), aName.toString() );
-
-        assertSame( jName, jName.add( jName.size(), "cn=five" ) );
-        assertNotSame( aName, aName.add( aName.size(), "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" );
@@ -2754,49 +2211,15 @@
         Dn aName = new Dn( "cn=four,cn=three,cn=two,cn=one" );
 
         assertEquals( jName.startsWith( new LdapName( "cn=seven,cn=six,cn=five" ) ),
-            aName.isChildOf( new Dn( "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.isChildOf( new Dn( "cn=three,cn=two,cn=one" ) ) );
+            aName.isDescendantOf( new Dn( "cn=three,cn=two,cn=one" ) ) );
     }
 
 
     /**
      * Test for DIRSERVER-191
-     */
-    @Test
-    public void testEndsWithName() throws LdapException, InvalidNameException
-    {
-        // Check with Dn
-        Dn n0 = new Dn( "cn=zero" );
-        Dn n10 = new Dn( "cn=one,cn=zero" );
-        Dn n210 = new Dn( "cn=two,cn=one,cn=zero" );
-        Dn n3210 = new Dn( "cn=three,cn=two,cn=one,cn=zero" );
-        Dn n321 = new Dn( "cn=three,cn=two,cn=one" );
-        Dn n32 = new Dn( "cn=three,cn=two" );
-        Dn n3 = new Dn( "cn=three" );
-        Dn n21 = new Dn( "cn=two,cn=one" );
-        Dn n2 = new Dn( "cn=two" );
-        Dn n1 = new Dn( "cn=one" );
-
-        assertTrue( n3210.hasSuffix( n3 ) );
-        assertTrue( n3210.hasSuffix( n32 ) );
-        assertTrue( n3210.hasSuffix( n321 ) );
-        assertTrue( n3210.hasSuffix( n3210 ) );
-
-        assertTrue( n210.hasSuffix( n2 ) );
-        assertTrue( n210.hasSuffix( n21 ) );
-        assertTrue( n210.hasSuffix( n210 ) );
-
-        assertTrue( n10.hasSuffix( n1 ) );
-        assertTrue( n10.hasSuffix( n10 ) );
-
-        assertTrue( n0.hasSuffix( n0 ) );
-    }
-
-
-    /**
-     * Test for DIRSERVER-191
-     */
+     *
     @Test
     public void testRemoveName() throws LdapException, InvalidNameException
     {
@@ -2808,31 +2231,12 @@
         assertNotSame( jName.toString(), aName.toString() );
 
         jName.remove( jName.size() - 1 );
-        assertEquals( jName.toString(), aName.remove( aName.size() - 1 ).remove( 0 ).toString() );
+        assertEquals( jName.toString(), aName.getParent().remove( 0 ).toString() );
         assertNotSame( jName.toString(), aName.toString() );
     }
 
 
     /**
-     * Test for DIRSERVER-191
-     *
-    @Test
-    public void testGetAllName() 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" );
-
-        Enumeration<String> j = jName.getAll();
-        Enumeration<String> a = aName.getAll();
-        while ( j.hasMoreElements() )
-        {
-            assertTrue( j.hasMoreElements() );
-            assertEquals( j.nextElement(), a.nextElement() );
-        }
-    }
-
-
-    /**
      * Test for DIRSERVER-642
      * @throws LdapException
      */
@@ -3091,74 +2495,6 @@
     }
 
 
-    private ByteArrayOutputStream serializeDN( Dn dn ) throws IOException
-    {
-        ObjectOutputStream oOut = null;
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-
-        try
-        {
-            oOut = new ObjectOutputStream( out );
-            oOut.writeObject( dn );
-        }
-        catch ( IOException ioe )
-        {
-            throw ioe;
-        }
-        finally
-        {
-            try
-            {
-                if ( oOut != null )
-                {
-                    oOut.flush();
-                    oOut.close();
-                }
-            }
-            catch ( IOException ioe )
-            {
-                throw ioe;
-            }
-        }
-
-        return out;
-    }
-
-
-    private Dn deserializeDN( ByteArrayOutputStream out ) throws IOException, ClassNotFoundException
-    {
-        ObjectInputStream oIn = null;
-        ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
-
-        try
-        {
-            oIn = new ObjectInputStream( in );
-
-            Dn dn = (Dn) oIn.readObject();
-
-            return dn;
-        }
-        catch ( IOException ioe )
-        {
-            throw ioe;
-        }
-        finally
-        {
-            try
-            {
-                if ( oIn != null )
-                {
-                    oIn.close();
-                }
-            }
-            catch ( IOException ioe )
-            {
-                throw ioe;
-            }
-        }
-    }
-
-
     /**
      * Test the serialization of a Dn
      *
@@ -3168,9 +2504,9 @@
     public void testNameSerialization() throws Exception
     {
         Dn dn = new Dn( "ou= Some   People   + dc=  And   Some anImAls,dc = eXample,dc= cOm" );
-        dn.normalize( oids );
+        dn.normalize( schemaManager );
 
-        assertEquals( dn, deserializeDN( serializeDN( dn ) ) );
+        assertEquals( dn, DnSerializer.deserialize( DnSerializer.serialize( dn ) ) );
     }
 
 
@@ -3179,7 +2515,7 @@
     {
         Dn dn = Dn.EMPTY_DN;
 
-        assertEquals( dn, deserializeDN( serializeDN( dn ) ) );
+        assertEquals( dn, DnSerializer.deserialize( DnSerializer.serialize( dn ) ) );
     }
 
 
@@ -3192,15 +2528,10 @@
     public void testNameStaticSerialization() throws Exception
     {
         Dn dn = new Dn( "ou= Some   People   + dc=  And   Some anImAls,dc = eXample,dc= cOm" );
-        dn.normalize( oids );
+        dn.normalize( schemaManager );
 
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        ObjectOutputStream out = new ObjectOutputStream( baos );
+        byte[] data = DnSerializer.serialize( dn );
 
-        DnSerializer.serialize( dn, out );
-        out.flush();
-
-        byte[] data = baos.toByteArray();
         ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( data ) );
 
         assertEquals( dn, DnSerializer.deserialize( in ) );
@@ -3271,7 +2602,7 @@
         ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( data ) );
 
         assertEquals( dn, DnSerializer.deserialize(in) );
-        assertEquals( dn, deserializeDN( serializeDN( dn ) ) );
+        assertEquals( dn, DnSerializer.deserialize( DnSerializer.serialize( dn ) ) );
     }
 
 
@@ -3355,32 +2686,32 @@
     public void testTrailingEscapedSpace() throws Exception
     {
         Dn dn1 = new Dn( "ou=A\\ ,ou=system" );
-        dn1.normalize( oids );
+        dn1.normalize( schemaManager );
         assertEquals( "ou=A\\ ,ou=system", dn1.getName() );
-        assertEquals( "ou=a,ou=system", dn1.getNormName() );
+        assertEquals( "2.5.4.11=a,2.5.4.11=system", dn1.getNormName() );
         assertEquals( "ou=A\\ ", dn1.getRdn().getName() );
-        assertEquals( "ou=a", dn1.getRdn().getNormName() );
+        assertEquals( "2.5.4.11=a", dn1.getRdn().getNormName() );
 
         Dn dn2 = new Dn( "ou=A\\20,ou=system" );
-        dn2.normalize( oids );
+        dn2.normalize( schemaManager );
         assertEquals( "ou=A\\20,ou=system", dn2.getName() );
-        assertEquals( "ou=a,ou=system", dn2.getNormName() );
+        assertEquals( "2.5.4.11=a,2.5.4.11=system", dn2.getNormName() );
         assertEquals( "ou=A\\20", dn2.getRdn().getName() );
-        assertEquals( "ou=a", dn2.getRdn().getNormName() );
+        assertEquals( "2.5.4.11=a", dn2.getRdn().getNormName() );
 
         Dn dn3 = new Dn( "ou=\\ ,ou=system" );
-        dn3.normalize( oids );
+        dn3.normalize( schemaManager );
         assertEquals( "ou=\\ ,ou=system", dn3.getName() );
-        assertEquals( "ou=\\ ,ou=system", dn3.getNormName() );
+        assertEquals( "2.5.4.11=\\ ,2.5.4.11=system", dn3.getNormName() );
         assertEquals( "ou=\\ ", dn3.getRdn().getName() );
-        assertEquals( "ou=\\ ", dn3.getRdn().getNormName() );
+        assertEquals( "2.5.4.11=\\ ", dn3.getRdn().getNormName() );
 
         Dn dn4 = new Dn( "ou=\\20,ou=system" );
-        dn4.normalize( oids );
+        dn4.normalize( schemaManager );
         assertEquals( "ou=\\20,ou=system", dn4.getName() );
-        assertEquals( "ou=\\ ,ou=system", dn4.getNormName() );
+        assertEquals( "2.5.4.11=\\ ,2.5.4.11=system", dn4.getNormName() );
         assertEquals( "ou=\\20", dn4.getRdn().getName() );
-        assertEquals( "ou=\\ ", dn4.getRdn().getNormName() );
+        assertEquals( "2.5.4.11=\\ ", dn4.getRdn().getNormName() );
     }
 
 
@@ -3427,7 +2758,7 @@
     {
         Dn dn = new Dn( "  ou  =  Example ,  ou  =  COM " );
 
-        dn.normalize( oidOids );
+        dn.normalize( schemaManager );
         assertEquals( "2.5.4.11=example,2.5.4.11=com", dn.getNormName() );
         assertEquals( "  ou  =  Example ,  ou  =  COM ", dn.getName() );
 
@@ -3457,7 +2788,7 @@
     {
         Dn dn = new Dn( "  ou  =  Example + ou = TEST ,  ou  =  COM " );
 
-        dn.normalize( oidOids );
+        dn.normalize( schemaManager );
         assertEquals( "2.5.4.11=example+2.5.4.11=test,2.5.4.11=com", dn.getNormName() );
         assertEquals( "  ou  =  Example + ou = TEST ,  ou  =  COM ", dn.getName() );
 
@@ -3508,7 +2839,7 @@
     {
         Dn dn = new Dn( "  ou  =  Ex\\+mple ,  ou  =  COM " );
 
-        dn.normalize( oidOids );
+        dn.normalize( schemaManager );
         assertEquals( "2.5.4.11=ex\\+mple,2.5.4.11=com", dn.getNormName() );
         assertEquals( "  ou  =  Ex\\+mple ,  ou  =  COM ", dn.getName() );
 
@@ -3589,7 +2920,7 @@
 
         // ------------------------------------------------------------------
         // Now normalize the Dn
-        dn.normalize( oidOids );
+        dn.normalize( schemaManager );
 
         assertEquals( "  OU  =  Ex\\+mple + ou = T\\+ST\\  ,  ou  =  COM ", dn.getName() );
         assertEquals( "2.5.4.11=ex\\+mple+2.5.4.11=t\\+st,2.5.4.11=com", dn.getNormName() );
@@ -3701,15 +3032,15 @@
         Dn parent3 = new Dn( "dc=org" );
         Dn notParent = new Dn( "ou=example,dc=apache, dc=com" );
 
-        assertTrue( parent1.isParentOf( dn ) );
-        assertTrue( parent2.isParentOf( dn ) );
-        assertTrue( parent3.isParentOf( dn ) );
-        assertFalse( notParent.isParentOf( dn ) );
+        assertTrue( parent1.isAncestorOf( dn ) );
+        assertTrue( parent2.isAncestorOf( dn ) );
+        assertTrue( parent3.isAncestorOf( dn ) );
+        assertFalse( notParent.isAncestorOf( dn ) );
     }
 
 
     @Test
-    public void testIsChildOfTrue() throws Exception
+    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" );
@@ -3717,10 +3048,10 @@
         Dn parent3 = new Dn( "dc=org" );
         Dn notParent = new Dn( "dc=apache, dc=com" );
 
-        assertTrue( dn.isChildOf( parent1 ) );
-        assertTrue( dn.isChildOf( parent2 ) );
-        assertTrue( dn.isChildOf( parent3 ) );
-        assertFalse( notParent.isChildOf( dn ) );
+        assertTrue( dn.isDescendantOf( parent1 ) );
+        assertTrue( dn.isDescendantOf( parent2 ) );
+        assertTrue( dn.isDescendantOf( parent3 ) );
+        assertFalse( notParent.isDescendantOf( dn ) );
     }
 
 
@@ -3733,16 +3064,16 @@
         dn = dn.add( "ou=users" );
         assertFalse( dn.isNormalized() );
 
-        dn.normalize( oidOids );
+        dn.normalize( schemaManager );
         assertTrue( dn.isNormalized() );
 
         dn = dn.add( "ou=x" );
-        assertFalse( dn.isNormalized() );
+        assertTrue( dn.isNormalized() );
 
-        assertEquals( "ou=x,2.5.4.11=users,2.5.4.11=system", dn.getNormName() );
+        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.normalize( oidOids );
+        dn.normalize( 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() );
 
@@ -3753,18 +3084,15 @@
         dn = dn.add( rdn );
         assertFalse( dn.isNormalized() );
 
-        dn.normalize( oidOids );
+        dn.normalize( schemaManager );
         assertTrue( dn.isNormalized() );
 
         Dn anotherDn = new Dn( "ou=x,ou=users" );
 
         dn = dn.addAll( anotherDn );
-        assertFalse( dn.isNormalized() );
-
-        dn.normalize( oidOids );
         assertTrue( dn.isNormalized() );
 
-        dn = dn.remove( 0 );
+        dn.normalize( schemaManager );
         assertTrue( dn.isNormalized() );
     }
 
@@ -3775,8 +3103,20 @@
         String dnStr = "dc=/vehicles/v1/";
 
         Dn dn = new Dn( dnStr );
-        dn.normalize( oids );
+        dn.normalize( 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/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/MultiThreadedTest.java b/integ/src/test/java/org/apache/directory/shared/ldap/name/MultiThreadedTest.java
similarity index 65%
rename from ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/MultiThreadedTest.java
rename to integ/src/test/java/org/apache/directory/shared/ldap/name/MultiThreadedTest.java
index 20074ac..3d9171e 100644
--- a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/MultiThreadedTest.java
+++ b/integ/src/test/java/org/apache/directory/shared/ldap/name/MultiThreadedTest.java
@@ -17,26 +17,26 @@
  *  under the License.
  *
  */
-package org.apache.directory.shared.ldap.model.name;
+package org.apache.directory.shared.ldap.name;
 
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import java.util.HashMap;
-import java.util.Map;
-
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.junit.tools.MultiThreadedMultiInvoker;
-import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
-import org.apache.directory.shared.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
-import org.apache.directory.shared.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.shared.ldap.model.name.Ava;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.name.Rdn;
+import org.apache.directory.shared.ldap.model.schema.SchemaManager;
+import org.apache.directory.shared.ldap.schemamanager.impl.DefaultSchemaManager;
 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 
@@ -50,8 +50,6 @@
     @Rule
     public MultiThreadedMultiInvoker i = new MultiThreadedMultiInvoker( 100, 1000 );
 
-    private static Map<String, OidNormalizer> oidsMap;
-
     private static Dn referenceDn;
     private static Dn sharedDn;
     private static Rdn referenceRdn;
@@ -59,30 +57,22 @@
     private static Ava referenceAva;
     private static Ava sharedAva;
 
+    private static SchemaManager schemaManager;
 
     @BeforeClass
-    public static void initMapOids() throws LdapInvalidDnException
+    public static void setup() throws Exception
     {
-        // Another map where we store OIDs instead of names.
-        oidsMap = new HashMap<String, OidNormalizer>();
-        oidsMap.put( "dc", new OidNormalizer( "0.9.2342.19200300.100.1.25", new DeepTrimToLowerNormalizer() ) );
-        oidsMap.put( "domaincomponent", new OidNormalizer( "0.9.2342.19200300.100.1.25",
-            new DeepTrimToLowerNormalizer() ) );
-        oidsMap.put( "0.9.2342.19200300.100.1.25", new OidNormalizer( "0.9.2342.19200300.100.1.25",
-            new DeepTrimToLowerNormalizer() ) );
-        oidsMap.put( "ou", new OidNormalizer( "2.5.4.11", new DeepTrimToLowerNormalizer() ) );
-        oidsMap.put( "organizationalUnitName", new OidNormalizer( "2.5.4.11", new DeepTrimToLowerNormalizer() ) );
-        oidsMap.put( "2.5.4.11", new OidNormalizer( "2.5.4.11", new DeepTrimToLowerNormalizer() ) );
+        schemaManager = new DefaultSchemaManager();
 
         referenceDn = new Dn( "dc=example,dc=com" );
-        referenceDn.normalize( oidsMap );
+        referenceDn.normalize( schemaManager );
         sharedDn = new Dn( "dc=example,dc=com" );
-        sharedDn.normalize( oidsMap );
+        sharedDn.normalize( schemaManager );
 
         referenceRdn = new Rdn( "ou=system" );
-        referenceRdn.normalize( oidsMap );
+        referenceRdn.normalize( schemaManager );
         sharedRdn = new Rdn( "ou=system" );
-        sharedRdn.normalize( oidsMap );
+        sharedRdn.normalize( schemaManager );
 
         referenceAva = new Ava( "ou", "2.5.4.11", "System", "system" );
         referenceAva.normalize();
@@ -96,10 +86,10 @@
     {
         sharedAva.normalize();
 
-        sharedRdn.normalize( oidsMap );
+        sharedRdn.normalize( schemaManager );
         assertTrue( sharedRdn.isNormalized() );
 
-        sharedDn.normalize( oidsMap );
+        sharedDn.normalize( schemaManager );
         assertTrue( sharedDn.isNormalized() );
     }
 
@@ -110,10 +100,10 @@
         sharedAva.normalize();
         assertEquals( referenceAva.hashCode(), sharedAva.hashCode() );
 
-        sharedRdn.normalize( oidsMap );
+        sharedRdn.normalize( schemaManager );
         assertEquals( referenceRdn.hashCode(), sharedRdn.hashCode() );
 
-        sharedDn.normalize( oidsMap );
+        sharedDn.normalize( schemaManager );
         assertEquals( referenceDn.hashCode(), sharedDn.hashCode() );
     }
 
@@ -126,12 +116,12 @@
         assertTrue( referenceAva.equals( sharedAva ) );
         assertTrue( sharedAva.equals( referenceAva ) );
 
-        sharedRdn.normalize( oidsMap );
+        sharedRdn.normalize( schemaManager );
         assertEquals( referenceRdn, sharedRdn );
         assertTrue( referenceRdn.equals( sharedRdn ) );
         assertTrue( sharedRdn.equals( referenceRdn ) );
 
-        sharedDn.normalize( oidsMap );
+        sharedDn.normalize( schemaManager );
         assertEquals( referenceDn, sharedDn );
         assertTrue( referenceDn.equals( sharedDn ) );
         assertTrue( sharedDn.equals( referenceDn ) );
@@ -145,13 +135,13 @@
         assertEquals( 0, sharedAva.compareTo( referenceAva ) );
         assertEquals( 0, referenceAva.compareTo( sharedAva ) );
 
-        sharedRdn.normalize( oidsMap );
+        sharedRdn.normalize( schemaManager );
         assertEquals( 0, referenceRdn.compareTo( sharedRdn ) );
         assertEquals( 0, sharedRdn.compareTo( referenceRdn ) );
 
-        sharedDn.normalize( oidsMap );
-        assertEquals( 0, referenceDn.compareTo( sharedDn ) );
-        assertEquals( 0, sharedDn.compareTo( referenceDn ) );
+        sharedDn.normalize( schemaManager );
+        assertEquals( referenceDn, sharedDn );
+        assertEquals( sharedDn, referenceDn );
     }
 
 }
diff --git a/integ/src/test/resources/log4j.properties b/integ/src/test/resources/log4j.properties
index facb3e6..9daa6e0 100644
--- a/integ/src/test/resources/log4j.properties
+++ b/integ/src/test/resources/log4j.properties
@@ -14,8 +14,9 @@
 #    See the License for the specific language governing permissions and
 #    limitations under the License.
 #############################################################################
-log4j.rootCategory=OFF, stdout
+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.shared.ldap.codec.standalone.StandaloneLdapCodecService=INFO
diff --git a/ldap-client-api/pom.xml b/ldap-client-api/pom.xml
index 65de1fc..7d27258 100644
--- a/ldap-client-api/pom.xml
+++ b/ldap-client-api/pom.xml
@@ -50,12 +50,23 @@
   <dependencies>
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>shared-ldap</artifactId>
+      <artifactId>shared-ldap-schema</artifactId>
     </dependency>
 
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>shared-ldap-schema</artifactId>
+      <artifactId>shared-ldap-codec-standalone</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-codec</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-extras-codec</artifactId>
     </dependency>
 
     <dependency>
diff --git a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/CramMd5Request.java b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/CramMd5Request.java
index 3a8d406..dab1688 100644
--- a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/CramMd5Request.java
+++ b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/CramMd5Request.java
@@ -25,14 +25,14 @@
 
 
 /**
- * Holds the data required to complete the SASL operation
+ * 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 CramMd5Request extends SaslRequest
-{   
+{
     /**
-     * TODO
+     * Creates a new instance of CramMd5Request.
      */
     public CramMd5Request()
     {
diff --git a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/DigestMd5Request.java b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/DigestMd5Request.java
index cd2d271..9787c14 100644
--- a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/DigestMd5Request.java
+++ b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/DigestMd5Request.java
@@ -25,14 +25,14 @@
 
 
 /**
- * Holds the data required to complete the SASL operation
+ * 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 DigestMd5Request extends SaslRequest
 {
     /**
-     * TODO
+     * Creates a new instance of DigestMd5Request.
      */
     public DigestMd5Request()
     {
diff --git a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/GssApiRequest.java b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/GssApiRequest.java
index 79e1e1a..c6867c0 100644
--- a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/GssApiRequest.java
+++ b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/GssApiRequest.java
@@ -21,11 +21,13 @@
 package org.apache.directory.ldap.client.api;
 
 
+import javax.security.auth.login.Configuration;
+
 import org.apache.directory.shared.ldap.model.constants.SupportedSaslMechanisms;
 
 
 /**
- * Holds the data required to complete the SASL operation
+ * Holds the data required to complete the GSS-API SASL operation
  *  
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
@@ -35,15 +37,32 @@
     protected String kdcHost;
 
     /** The KDC port */
-    protected int kdcPort;
+    protected int kdcPort = 0;
+
+    /** The krb5.conf file absolute path */
+    protected String krb5ConfFilePath;
+
+    /** The {@link javax.security.auth.login.Configuration} object for Login Module */
+    protected Configuration loginModuleConfiguration;
 
 
     /**
-     * TODO
+     * Creates a new instance of GssApiRequest.
      */
     public GssApiRequest()
     {
-        super( SupportedSaslMechanisms.CRAM_MD5 );
+        super( SupportedSaslMechanisms.GSSAPI );
+    }
+
+
+    /**
+     * 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;
     }
 
 
@@ -70,6 +89,28 @@
 
 
     /**
+     * Gets the (absolute) path to the 'krb5.conf' file.
+     *
+     * @return the (absolute) path to the 'krb5.conf' file
+     */
+    public String getKrb5ConfFilePath()
+    {
+        return krb5ConfFilePath;
+    }
+
+
+    /**
+     * 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;
+    }
+
+
+    /**
      * Sets the KDC host.
      *
      * @param kdcHost the KDC host
@@ -92,6 +133,17 @@
 
 
     /**
+     * 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;
+    }
+
+
+    /**
      * {@inheritDoc}
      */
     // Overriding the visibility of the method to public
diff --git a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
index 1ef09b0..4c27aed 100644
--- a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
+++ b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
@@ -28,6 +28,7 @@
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -57,18 +58,18 @@
 import org.apache.directory.ldap.client.api.future.SearchFuture;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.util.OID;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.api.LdapCodecServiceFactory;
 import org.apache.directory.shared.ldap.codec.api.MessageEncoderException;
-import org.apache.directory.shared.ldap.extras.extended.AddNoDResponse;
-import org.apache.directory.shared.ldap.extras.extended.BindNoDResponse;
-import org.apache.directory.shared.ldap.extras.extended.CompareNoDResponse;
-import org.apache.directory.shared.ldap.extras.extended.DeleteNoDResponse;
-import org.apache.directory.shared.ldap.extras.extended.ExtendedNoDResponse;
-import org.apache.directory.shared.ldap.extras.extended.ModifyDnNoDResponse;
-import org.apache.directory.shared.ldap.extras.extended.ModifyNoDResponse;
-import org.apache.directory.shared.ldap.extras.extended.NoticeOfDisconnect;
-import org.apache.directory.shared.ldap.extras.extended.SearchNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.AddNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.BindNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.CompareNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.DeleteNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.ExtendedNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.ModifyDnNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.ModifyNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.NoticeOfDisconnect;
+import org.apache.directory.shared.ldap.model.message.extended.SearchNoDResponse;
 import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
 import org.apache.directory.shared.ldap.model.cursor.Cursor;
 import org.apache.directory.shared.ldap.model.cursor.SearchCursor;
@@ -122,6 +123,15 @@
 import org.apache.directory.shared.ldap.model.message.UnbindRequest;
 import org.apache.directory.shared.ldap.model.message.UnbindRequestImpl;
 import org.apache.directory.shared.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.shared.ldap.model.message.extended.AddNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.BindNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.CompareNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.DeleteNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.ExtendedNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.ModifyDnNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.ModifyNoDResponse;
+import org.apache.directory.shared.ldap.model.message.extended.NoticeOfDisconnect;
+import org.apache.directory.shared.ldap.model.message.extended.SearchNoDResponse;
 import org.apache.directory.shared.ldap.model.name.Dn;
 import org.apache.directory.shared.ldap.model.name.Rdn;
 import org.apache.directory.shared.ldap.model.schema.AttributeType;
@@ -213,7 +223,7 @@
     private SchemaManager schemaManager;
 
     /** the ldap codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
+    LdapCodecService codec = LdapCodecServiceFactory.getSingleton();
 
     /** The Ldap codec protocol filter */
     private IoFilter ldapProtocolFilter = new ProtocolCodecFilter( codec.newProtocolCodecFactory( true ) );
@@ -535,7 +545,7 @@
         CloseFuture closeFuture = connectionFuture.getSession().getCloseFuture();
 
         // Add a listener to close the session in the session.
-        closeFuture.addListener( ( IoFutureListener<?> ) new IoFutureListener<IoFuture>()
+        closeFuture.addListener( new IoFutureListener<IoFuture>()
         {
             public void operationComplete( IoFuture future )
             {
@@ -1387,10 +1397,11 @@
         System.setProperty( "java.security.krb5.conf", krbConfPath );
 
         Configuration.setConfiguration( new Krb5LoginConfiguration() );
-        System.setProperty( "javax.security.auth.useSubjectCredsOnly", "true" );
+	System.setProperty( "javax.security.auth.useSubjectCredsOnly", "true" );
 
         try
         {
+            System.setProperty( "javax.security.auth.useSubjectCredsOnly", "true" );
             LoginContext loginContext = new LoginContext( "ldapnetworkconnection",
                         new SaslCallbackHandler( request ) );
             loginContext.login();
@@ -1629,11 +1640,12 @@
 
     /**
      * 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 );
@@ -1676,11 +1688,12 @@
     /**
      * 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
@@ -1859,13 +1872,13 @@
                 if ( responseFuture instanceof SearchFuture )
                 {
                     intermediateResponse = new IntermediateResponseImpl( messageId );
-                    addControls( intermediateResponse, ( IntermediateResponse ) response );
+                    addControls( intermediateResponse, response );
                     ( ( SearchFuture ) responseFuture ).set( intermediateResponse );
                 }
                 else if ( responseFuture instanceof ExtendedFuture )
                 {
                     intermediateResponse = new IntermediateResponseImpl( messageId );
-                    addControls( intermediateResponse, ( IntermediateResponse ) response );
+                    addControls( intermediateResponse, response );
                     ( ( ExtendedFuture ) responseFuture ).set( intermediateResponse );
                 }
                 else
@@ -3055,7 +3068,7 @@
         }
         catch ( LdapNoPermissionException lnpe )
         {
-            // Special case to deal with insufficient permissions 
+            // Special case to deal with insufficient permissions
             return false;
         }
         catch ( LdapException le )
@@ -3226,9 +3239,9 @@
 
     /**
      * loads schema using the specified schema loader
-     * 
+     *
      * @param loader the {@link SchemaLoader} to be used to load schema
-     * @throws LdapException 
+     * @throws LdapException
      */
     public void loadSchema( SchemaLoader loader ) throws LdapException
     {
@@ -3387,7 +3400,6 @@
         {
             for ( Control cc : controls.values() )
             {
-                // FIXME why the cc is coming as null!?
                 if ( cc == null )
                 {
                     continue;
@@ -3484,7 +3496,8 @@
 
     /**
      * Sends the StartTLS extended request to server and adds a security layer
-     * upon receiving a response with successful result
+     * upon receiving a response with successful result. Note that we will use
+     * the default LDAP connection.
      *
      * @throws LdapException
      */
@@ -3518,7 +3531,7 @@
 
 
     /**
-     * adds {@link SslFilter} to the IOConnector or IOSession's filter chain 
+     * adds {@link SslFilter} to the IOConnector or IOSession's filter chain
      */
     private void addSslFilter() throws LdapException
     {
@@ -3606,6 +3619,7 @@
             byte[] response = null;
             ResultCodeEnum result = null;
 
+            // Creating a SASL Client
             SaslClient sc = Sasl.createSaslClient(
                 new String[]
                     { bindRequest.getSaslMechanism() },
@@ -3624,13 +3638,13 @@
                 throw new LdapException( message );
             }
 
-            // Corner case : the SASL mech might send an initial challenge, and we have to 
+            // 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 
+                // Stores the challenge's response, and send it to the server
                 bindRequest.setCredentials( challengeResponse );
                 writeBindRequest( bindRequest );
 
@@ -3742,13 +3756,13 @@
 
     /**
      * 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 
+     *
+     * 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
@@ -3758,7 +3772,7 @@
      *         kdc = localhost:6088
      *     }
      * </pre>
-     * 
+     *
      * @return the full path of the config file
      */
     private String createKrbConfFile( String realmName, String kdcHost, int kdcPort ) throws IOException
diff --git a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/SaslRequest.java b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/SaslRequest.java
index 0941f48..7b24bd6 100644
--- a/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/SaslRequest.java
+++ b/ldap-client-api/src/main/java/org/apache/directory/ldap/client/api/SaslRequest.java
@@ -25,6 +25,8 @@
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.directory.shared.ldap.model.constants.SaslQoP;
+import org.apache.directory.shared.ldap.model.constants.SaslSecurityStrength;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.util.StringConstants;
 import org.apache.directory.shared.util.Strings;
@@ -57,9 +59,14 @@
     protected String authorizationId;
 
 
+    /**
+     * Creates a new instance of SaslRequest.
+     *
+     * @param saslMechanism
+     *      the SASL mechanism
+     */
     protected SaslRequest( String saslMechanism )
     {
-        super();
         this.saslMechanism = saslMechanism;
     }
 
diff --git a/ldap-codec-standalone/pom.xml b/ldap-codec-standalone/pom.xml
new file mode 100644
index 0000000..c2c6fa8
--- /dev/null
+++ b/ldap-codec-standalone/pom.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT 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.shared</groupId>
+    <artifactId>shared-parent</artifactId>
+    <version>1.0.0-M2-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>shared-ldap-codec-standalone</artifactId>
+  <name>Apache Directory Shared LDAP 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>shared-ldap-codec</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.framework</artifactId>
+    </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>
+              ${project.build.directory}/osgi-cache
+            </org.osgi.framework.storage>
+          </systemPropertyVariables>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/ldap-codec-standalone/src/checkstyle/suppressions.xml b/ldap-codec-standalone/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..74a4604
--- /dev/null
+++ b/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/ldap/src/main/appended-resources/META-INF/LICENSE b/ldap-codec-standalone/src/main/appended-resources/META-INF/LICENSE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/LICENSE
copy to ldap-codec-standalone/src/main/appended-resources/META-INF/LICENSE
diff --git a/ldap/src/main/appended-resources/META-INF/NOTICE b/ldap-codec-standalone/src/main/appended-resources/META-INF/NOTICE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/NOTICE
copy to ldap-codec-standalone/src/main/appended-resources/META-INF/NOTICE
diff --git a/ldap-codec-standalone/src/main/java/org/apache/directory/shared/ldap/codec/standalone/CodecHostActivator.java b/ldap-codec-standalone/src/main/java/org/apache/directory/shared/ldap/codec/standalone/CodecHostActivator.java
new file mode 100644
index 0000000..0105637
--- /dev/null
+++ b/ldap-codec-standalone/src/main/java/org/apache/directory/shared/ldap/codec/standalone/CodecHostActivator.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.shared.ldap.codec.standalone;
+
+
+import java.io.File;
+import java.io.FileFilter;
+
+import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * The {@link BundleActivator} for the codec. This implementation class is 
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CodecHostActivator implements BundleActivator
+{
+    private StandaloneLdapCodecService codec;
+    private ServiceRegistration registration;
+    private BundleContext bundleContext;
+    
+    
+    public CodecHostActivator( StandaloneLdapCodecService codec )
+    {
+        this.codec = codec;
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void start( BundleContext bundleContext ) throws Exception
+    {
+        this.bundleContext = bundleContext;
+        
+        registration = bundleContext.registerService( LdapCodecService.class.getName(), codec, null );
+        
+        if ( codec.getPluginDirectory() != null )
+        {
+            File[] files = codec.getPluginDirectory().listFiles( new FileFilter()
+            {
+                public boolean accept( File pathname )
+                {
+                    return 
+                        pathname.canRead()
+                        &&
+                        pathname.isFile() 
+                        && 
+                        pathname.getAbsolutePath().endsWith( ".jar" );
+                }
+            });
+            
+            for ( File file : files )
+            {
+                Bundle bundle = bundleContext.installBundle( file.toURI().toURL().toExternalForm() );
+                bundle.start();
+            }
+        }
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop( BundleContext bundleContext ) throws Exception
+    {
+        registration.unregister();
+        
+        this.bundleContext = null;
+    }
+    
+    
+    /**
+     * Gets the Bundles installed.
+     * 
+     * @return The Bundles installed.
+     */
+    public Bundle[] getBundles()
+    {
+        if ( bundleContext != null )
+        {
+            return bundleContext.getBundles();
+        }
+        
+        return null;
+    }
+}
diff --git a/ldap-codec-standalone/src/main/java/org/apache/directory/shared/ldap/codec/standalone/StandaloneLdapCodecService.java b/ldap-codec-standalone/src/main/java/org/apache/directory/shared/ldap/codec/standalone/StandaloneLdapCodecService.java
new file mode 100644
index 0000000..f89d3b4
--- /dev/null
+++ b/ldap-codec-standalone/src/main/java/org/apache/directory/shared/ldap/codec/standalone/StandaloneLdapCodecService.java
@@ -0,0 +1,780 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.shared.ldap.codec.standalone;
+
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.ldap.codec.BasicControlDecorator;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.api.ControlFactory;
+import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
+import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.api.UnsolicitedResponseFactory;
+import org.apache.directory.shared.ldap.codec.controls.cascade.CascadeFactory;
+import org.apache.directory.shared.ldap.codec.controls.manageDsaIT.ManageDsaITFactory;
+import org.apache.directory.shared.ldap.codec.controls.search.entryChange.EntryChangeFactory;
+import org.apache.directory.shared.ldap.codec.controls.search.pagedSearch.PagedResultsFactory;
+import org.apache.directory.shared.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory;
+import org.apache.directory.shared.ldap.codec.controls.search.subentries.SubentriesFactory;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.protocol.mina.LdapProtocolCodecFactory;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
+import org.apache.directory.shared.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.shared.util.exception.NotImplementedException;
+import org.apache.felix.framework.Felix;
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The default {@link org.apache.directory.shared.ldap.codec.api.LdapCodecService} implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class StandaloneLdapCodecService implements LdapCodecService
+{
+    /** Missing felix constants for cache directory locking */
+    public static final String FELIX_CACHE_LOCKING = "felix.cache.locking";
+
+    /** Missing felix constants for cache root directory path */
+    public static final String FELIX_CACHE_ROOTDIR = "felix.cache.rootdir";
+
+    /** A logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StandaloneLdapCodecService.class );
+    
+    /**
+     * This should be constructed at class initialization time by reading the
+     * Export-Package attribute of the this jar's manifest file.
+     */
+    private static final String[] SYSTEM_PACKAGES =
+    {
+        "org.slf4j; version=1.6.0",
+        "org.apache.directory.shared.i18n; version=1.0.0",
+        "org.apache.directory.shared.util; version=1.0.0",
+        "org.apache.directory.shared.util.exception; version=1.0.0",
+        "org.apache.directory.shared.asn1; version=1.0.0",
+        "org.apache.directory.shared.asn1.util; version=1.0.0",
+        "org.apache.directory.shared.asn1.ber; version=1.0.0",
+        "org.apache.directory.shared.asn1.ber.tlv; version=1.0.0",
+        "org.apache.directory.shared.asn1.ber.grammar; version=1.0.0",
+        "org.apache.directory.shared.asn1.actions; version=1.0.0",
+        "org.apache.directory.shared.ldap.asn1.ber; version=1.0.0",
+        "org.apache.directory.shared.ldap.model; version=1.0.0",
+        "org.apache.directory.shared.ldap.model.exception; version=1.0.0",
+        "org.apache.directory.shared.ldap.model.filter; version=1.0.0",
+        "org.apache.directory.shared.ldap.model.name; version=1.0.0",
+        "org.apache.directory.shared.ldap.model.entry; version=1.0.0",
+        "org.apache.directory.shared.ldap.model.schema; version=1.0.0",
+        "org.apache.directory.shared.ldap.model.message; version=1.0.0",
+        "org.apache.directory.shared.ldap.model.message.controls; version=1.0.0",
+        "org.apache.directory.shared.ldap.codec.controls; version=1.0.0",
+        "org.apache.directory.shared.ldap.codec.api; version=1.0.0"
+    };
+ 
+    /** System property checked if the pluginProperty is null */
+    public static final String PLUGIN_DIRECTORY_PROPERTY = "codec.plugin.directory";
+    
+    /** The map of registered {@link org.apache.directory.shared.ldap.codec.api.ControlFactory}'s */
+    private Map<String,ControlFactory<?,?>> controlFactories = new HashMap<String, ControlFactory<?,?>>();
+
+    /** The map of registered {@link org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory}'s by request OID */
+    private Map<String,ExtendedRequestFactory<?,?>> extReqFactories = new HashMap<String, ExtendedRequestFactory<?,?>>();
+
+    /** The map of registered {@link UnsolicitedResponseFactory}'s by request OID */
+    private Map<String,UnsolicitedResponseFactory<?>> unsolicitedFactories = new HashMap<String, UnsolicitedResponseFactory<?>>();
+    
+    /** The codec's {@link BundleActivator} */
+    private CodecHostActivator activator;
+    
+    /** The embedded {@link Felix} instance */
+    private Felix felix;
+
+    /** Felix's bundle cache directory */
+    private final File cacheDirectory;
+    
+    /** The plugin (bundle) containing directory to load codec extensions from */
+    private final File pluginDirectory;
+    
+    
+    /**
+     * Creates a new instance of StandaloneLdapCodecService. Optionally checks for
+     * system property {@link #PLUGIN_DIRECTORY_PROPERTY}. 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;shared-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 StandaloneLdapCodecService()
+    {
+        this( null, null );
+    }
+    
+    
+    /**
+     * Uses system properties and default considerations to create a cache 
+     * directory that can be used when one is not provided.
+     *
+     * @see FelixConstants#FRAMEWORK_STORAGE
+     * @return The cache directory default.
+     */
+    private File getCacheDirectoryDefault()
+    {
+        String frameworkStorage = System.getProperties().getProperty( FelixConstants.FRAMEWORK_STORAGE );
+        LOG.info( "{}: {}", FelixConstants.FRAMEWORK_STORAGE, frameworkStorage );
+        
+        String felixCacheRootdir = System.getProperties().getProperty( FELIX_CACHE_ROOTDIR );
+        LOG.info( "{}: {}", FELIX_CACHE_ROOTDIR, felixCacheRootdir );
+
+        try
+        {
+            if ( frameworkStorage == null && felixCacheRootdir == null )
+            {
+                return new File( File.createTempFile( "dummy", null ).getParentFile(), 
+                    "osgi-cache-" + Integer.toString( this.hashCode() ) );
+            }
+            else if ( frameworkStorage == null && felixCacheRootdir != null )
+            {
+                return new File( new File ( felixCacheRootdir ), 
+                    "osgi-cache-" + Integer.toString( this.hashCode() ) );
+            }
+            else if ( frameworkStorage != null && felixCacheRootdir == null )
+            {
+                return new File( frameworkStorage + "-" + Integer.toString( this.hashCode() ) );
+            }
+            
+            // else if both are not null now
+            return new File( new File ( felixCacheRootdir ), 
+                frameworkStorage + "-" + Integer.toString( this.hashCode() ) );
+        }
+        catch ( Exception e ) 
+        {
+            String message = "Failure to create temporary cache directory: " + e.getMessage();
+            LOG.warn( message, e );
+            return null;
+        }
+    }
+    
+    
+    /**
+     * Gets the optional system property value for the pluginDirectory if one 
+     * is provided.
+     *
+     * @return The path for the pluginDirectory or null if not provided.
+     */
+    private File getPluginDirectoryDefault()
+    {
+        String value = System.getProperty( StandaloneLdapCodecService.PLUGIN_DIRECTORY_PROPERTY );
+        LOG.info( "{}: {}", PLUGIN_DIRECTORY_PROPERTY, value );
+        
+        if ( value == null )
+        {
+            return null;
+        }
+        
+        return new File( value );
+    }
+    
+    
+    /**
+     * Creates a new instance of StandaloneLdapCodecService.
+     */
+    public StandaloneLdapCodecService( File pluginDirectory, File cacheDirectory )
+    {
+        
+        // -------------------------------------------------------------------
+        // Handle plugin directory
+        // -------------------------------------------------------------------
+
+        if ( pluginDirectory == null )
+        {
+            this.pluginDirectory = getPluginDirectoryDefault();
+            LOG.info( "Null plugin directory provided, using default instead: {}", this.pluginDirectory );
+        }
+        else
+        {
+            this.pluginDirectory = pluginDirectory;
+            LOG.info( "Valid plugin directory provided: {}", this.pluginDirectory );
+        }
+        
+        if ( this.pluginDirectory == null )
+        {
+            // do nothing
+        }
+        else if ( ! this.pluginDirectory.exists() )
+        {
+            this.pluginDirectory.mkdirs();
+        }
+        
+        if ( this.pluginDirectory == null )
+        {
+            // do nothing
+        }
+        else if ( ! this.pluginDirectory.isDirectory() )
+        {
+            String msg = "The provided plugin directory is not a directory:" + this.pluginDirectory.getAbsolutePath();
+            LOG.error( msg );
+            throw new IllegalArgumentException( msg );
+        }
+        else if ( ! this.pluginDirectory.canRead() )
+        {
+            String msg = "The provided plugin directory is not readable:" + this.pluginDirectory.getAbsolutePath();
+            LOG.error( msg );
+            throw new IllegalArgumentException( msg );
+        }
+
+        
+        // -------------------------------------------------------------------
+        // Handle cache directory
+        // -------------------------------------------------------------------
+        
+        if ( cacheDirectory == null )
+        {
+            this.cacheDirectory = getCacheDirectoryDefault();
+            LOG.info( "Null cache directory provided, using default instead: {}", this.cacheDirectory );
+        }
+        else
+        {
+            this.cacheDirectory = cacheDirectory;
+            LOG.info( "Valid cache directory provided: {}", this.cacheDirectory );
+        }
+        
+        if ( this.cacheDirectory == null )
+        {
+            // do nothing
+        }
+        else if ( ! this.cacheDirectory.exists() )
+        {
+            this.cacheDirectory.mkdirs();
+        }
+        
+        if ( this.cacheDirectory == null )
+        {
+            // do nothing
+        }
+        else if ( ! this.cacheDirectory.isDirectory() )
+        {
+            String msg = "The provided cache directory is not a directory:" + this.cacheDirectory.getAbsolutePath();
+            LOG.error( msg );
+            throw new IllegalArgumentException( msg );
+        }
+        else if ( ! this.cacheDirectory.canRead() )
+        {
+            String msg = "The provided cache directory is not readable:" + this.cacheDirectory.getAbsolutePath();
+            LOG.error( msg );
+            throw new IllegalArgumentException( msg );
+        }
+        
+        loadStockControls();
+        setupFelix();
+    }
+    
+    
+    /**
+     * Assembles the <code>org.osgi.framework.system.packages.extra</code> list
+     * of system packages exported by the embedding host to interact with bundles
+     * running inside {@link Felix}.
+     * 
+     * @return A comma delimited list of exported host packages.
+     */
+    private String getSystemPackages()
+    {
+        StringBuilder sb = new StringBuilder();
+        int ii = 0;
+        
+        do
+        {
+            // add comma if we're not at start and have more left
+            if ( ii > 0 && ii < SYSTEM_PACKAGES.length )
+            {
+                sb.append( ',' );
+            }
+            
+            sb.append( SYSTEM_PACKAGES[ii] );
+            ii++;
+        }
+        while( ii < SYSTEM_PACKAGES.length );
+        
+        LOG.info( "System packages shared by host: " + SYSTEM_PACKAGES );
+        
+        return sb.toString();
+    }
+    
+    
+    /**
+     * Sets up a {@link Felix} instance.
+     */
+    private void setupFelix()
+    {
+        // initialize activator and setup system bundle activators
+        activator = new CodecHostActivator( this );
+        List<BundleActivator> activators = new ArrayList<BundleActivator>();
+        activators.add( activator );
+        
+        // setup configuration for felix 
+        Map<String, Object> config = new HashMap<String, Object>();
+        config.put( FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, activators );
+        config.put( FelixConstants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, getSystemPackages() );
+        config.put( FELIX_CACHE_ROOTDIR, this.cacheDirectory.getParent() );
+        config.put( FelixConstants.FRAMEWORK_STORAGE, this.cacheDirectory.getName() );
+        
+        if ( System.getProperties().getProperty( FelixConstants.FRAMEWORK_STORAGE_CLEAN ) != null )
+        {
+            String cleanMode = System.getProperties().getProperty( FelixConstants.FRAMEWORK_STORAGE_CLEAN );
+            config.put( FelixConstants.FRAMEWORK_STORAGE_CLEAN, cleanMode );
+            LOG.info( "Using framework storage clean value from sytem properties: {}", cleanMode );
+        }
+        else
+        {
+            config.put( FelixConstants.FRAMEWORK_STORAGE_CLEAN, "none" );
+            LOG.info( "Using framework storage clean defaults: none" );
+        }
+
+        if ( System.getProperties().getProperty( FELIX_CACHE_LOCKING ) != null )
+        {
+            String lockCache = System.getProperties().getProperty( FELIX_CACHE_LOCKING );
+            config.put( FELIX_CACHE_LOCKING, lockCache );
+            LOG.info( "Using framework cache locking setting from sytem properties: {}", lockCache );
+        }
+        else
+        {
+            config.put( FELIX_CACHE_LOCKING, "true" );
+            LOG.info( "Using default for cache locking: enabled" );
+        }
+        
+        // instantiate and start up felix
+        felix = new Felix( config );
+        try
+        {
+            felix.start();
+        }
+        catch ( BundleException e )
+        {
+            String message = "Failed to start embedded felix instance: " + e.getMessage();
+            LOG.error( message, e );
+            throw new RuntimeException( message, e );
+        }
+    }
+    
+    
+    /**
+     * Shuts down the codec and its embedded {@link Felix} instance.
+     */
+    public void shutdown()
+    {
+        LOG.info( "Attempt to shutdown the codec service" );
+        
+        try
+        {
+            felix.stop();
+            felix.waitForStop( 0 );
+        }
+        catch ( Exception e )
+        {
+            String message = "Failed to stop embedded felix instance: " + e.getMessage();
+            LOG.error( message, e );
+            throw new RuntimeException( message, e );
+        }
+    }
+    
+    
+    /**
+     * Loads the Controls implement out of the box in the codec.
+     */
+    private void loadStockControls()
+    {
+        ControlFactory<?, ?> factory = new CascadeFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+        
+        factory = new EntryChangeFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+        
+        factory = new ManageDsaITFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+        
+        factory = new PagedResultsFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+        
+        factory = new PersistentSearchFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+
+        factory = new SubentriesFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.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( extReqFactories.keySet() ).iterator();
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequestFactory<?, ?> registerExtendedRequest( ExtendedRequestFactory<?,?> factory )
+    {
+        return extReqFactories.put( factory.getOid(), factory );
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     * 
+     * @TODO - finish this up and add factory registration capabilities,
+     * of course there is one default mechanism for now.
+     */
+    public ProtocolCodecFactory newProtocolCodecFactory( boolean client )
+    {
+        if ( client )
+        {
+            return new LdapProtocolCodecFactory( this );
+        }
+        else
+        {
+            throw new NotImplementedException( 
+                "Filters may be different here, and we're probably going to " +
+                "want to have a protocol codec factory registration mechanism" +
+                "since this way we can swap in and out MINA/Grizzly" );
+        }
+    }
+
+    
+    /**
+     * {@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 (org.apache.directory.shared.ldap.codec.api.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();
+        javax.naming.ldap.BasicControl jndiControl = 
+            new javax.naming.ldap.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 );
+    }
+
+
+    /**
+     * Gets the plugin directory containing codec extension bundles to load. 
+     * If null, the service checks to see if system properties were used to 
+     * specify the plugin directory. 
+     *
+     * @see {@link #PLUGIN_DIRECTORY_PROPERTY}
+     * @return The directory containing plugins.
+     */
+    public File getPluginDirectory()
+    {
+        return pluginDirectory;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> registeredUnsolicitedResponses()
+    {
+        return Collections.unmodifiableSet( unsolicitedFactories.keySet() ).iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnsolicitedResponseFactory<?> registerUnsolicitedResponse( UnsolicitedResponseFactory<?> factory )
+    {
+        return unsolicitedFactories.put( factory.getOid(), factory );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public javax.naming.ldap.ExtendedResponse toJndi( final ExtendedResponse modelResponse ) throws EncoderException
+    {
+        final byte[] encodedValue = new byte[ modelResponse.getEncodedValue().length ];
+        System.arraycopy( modelResponse.getEncodedValue(), 0, encodedValue, 0, modelResponse.getEncodedValue().length );
+        
+        return new javax.naming.ldap.ExtendedResponse()
+        {
+            private static final long serialVersionUID = 2955142105375495493L;
+
+            public String getID()
+            {
+                return modelResponse.getID();
+            }
+
+            public byte[] getEncodedValue()
+            {
+                return encodedValue;
+            }
+        };
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse fromJndi( javax.naming.ldap.ExtendedResponse jndiResponse ) throws DecoderException
+    {   
+        ExtendedResponse modelResponse;
+        ExtendedRequestFactory<?,?> extendedRequestFactory = extReqFactories.get( jndiResponse.getID() );
+        UnsolicitedResponseFactory<?> unsolicitedResponseFactory = unsolicitedFactories.get( jndiResponse.getID() );
+        
+        if ( unsolicitedResponseFactory != null )
+        {
+            modelResponse = unsolicitedResponseFactory.newResponse( jndiResponse.getEncodedValue() );
+        }
+        else if ( extendedRequestFactory != null )
+        {
+            modelResponse = extendedRequestFactory.newResponse( jndiResponse.getEncodedValue() );
+        }
+        else
+        {
+            modelResponse = new ExtendedResponseImpl( jndiResponse.getID() );
+            modelResponse.setResponseValue( jndiResponse.getEncodedValue() );
+        }
+        
+        return modelResponse;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequestFactory<?, ?> unregisterExtendedRequest( String oid )
+    {
+        return extReqFactories.remove( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnsolicitedResponseFactory<?> unregisterUnsolicitedResponse( String oid )
+    {
+        return unsolicitedFactories.remove( oid );
+    }
+}
diff --git a/ldap/src/site/site.xml b/ldap-codec-standalone/src/site/site.xml
similarity index 100%
copy from ldap/src/site/site.xml
copy to ldap-codec-standalone/src/site/site.xml
diff --git a/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapControlTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapControlTest.java
new file mode 100644
index 0000000..3f346a9
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapControlTest.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.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.AbandonRequestDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.AbandonRequest;
+import org.apache.directory.shared.ldap.model.message.AbandonRequestImpl;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@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.getMessageId() );
+        internalAbandonRequest.setAbandoned( abandonRequest.getAbandoned() );
+
+        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.shared.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.shared.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.shared.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.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapDecoderTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapDecoderTest.java
new file mode 100644
index 0000000..fe10ce5
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapDecoderTest.java
@@ -0,0 +1,570 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.ldap.codec;
+
+
+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.InputStream;
+import java.nio.ByteBuffer;
+import java.util.Queue;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.BindRequest;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.util.Strings;
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.mina.core.filterchain.IoFilter.NextFilter;
+import org.apache.mina.core.session.DummySession;
+import org.apache.mina.core.session.IoSession;
+import org.apache.mina.filter.codec.AbstractProtocolDecoderOutput;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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
+{
+    
+    private static class LdapProtocolDecoderOutput extends AbstractProtocolDecoderOutput 
+    {
+        public LdapProtocolDecoderOutput()
+        {
+            // Do nothing
+        }
+        
+        public void flush( NextFilter nextFilter, IoSession session ) 
+        {
+            // Do nothing
+            Queue<Object> messageQueue = getMessageQueue();
+            
+            while ( !messageQueue.isEmpty() ) 
+            {
+                nextFilter.messageReceived( session, messageQueue.poll()) ;
+            }
+        }
+
+
+        public Object getMessage()
+        {
+            Queue<Object> messageQueue = getMessageQueue();
+
+            if ( !messageQueue.isEmpty() )
+            {
+                return messageQueue.poll();
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }
+    
+    /**
+     * Test the decoding of a full PDU
+     */
+    @Test
+    public void testDecodeFull()
+    {
+        LdapDecoder ldapDecoder = new LdapDecoder();
+        LdapMessageContainer<MessageDecorator<? extends Message>> container = 
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+        ldapDecoder.setLdapMessageContainer( container );
+
+        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();
+
+        InputStream is = new ByteArrayInputStream(stream.array());
+        Object result = null;
+
+        // Decode a BindRequest PDU
+        try
+        {
+            result = ldapDecoder.decode(null, is);
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        BindRequest bindRequest = (BindRequest) result;
+
+        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
+    {
+        LdapDecoder ldapDecoder = new LdapDecoder();
+        LdapMessageContainer<MessageDecorator<? extends Message>> container = 
+            new LdapMessageContainer<MessageDecorator<? extends Message>>( codec );
+        ldapDecoder.setLdapMessageContainer( container );
+
+        IoSession dummySession = new DummySession();
+        dummySession.setAttribute( "messageContainer", container );
+
+        IoBuffer stream = IoBuffer.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();
+
+        ProtocolDecoderOutput result = new LdapProtocolDecoderOutput();
+
+        // Decode a BindRequest PDU
+        try
+        {
+            ldapDecoder.decode( dummySession, stream, result );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+
+        // Check the decoded PDU
+        BindRequest bindRequest = (BindRequest) ( ( LdapProtocolDecoderOutput ) result ).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()) );
+        
+        // The second message
+        bindRequest = ( BindRequest ) ( ( LdapProtocolDecoderOutput ) result ).getMessage();
+
+        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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapMessageTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapMessageTest.java
new file mode 100644
index 0000000..fa948b3
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapMessageTest.java
@@ -0,0 +1,339 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.UnbindRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.UnbindRequest;
+import org.apache.directory.shared.ldap.model.message.UnbindRequestImpl;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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
+{
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * 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( 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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapResultTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapResultTest.java
new file mode 100644
index 0000000..ba56765
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/LdapResultTest.java
@@ -0,0 +1,597 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.ldap.codec.decorators.AddResponseDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.AddResponse;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.Referral;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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
+{
+
+    // ~ Methods
+    // ------------------------------------------------------------------------------------
+
+    /**
+     * 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().getErrorMessage() );
+
+        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().getErrorMessage() );
+
+        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().getErrorMessage() );
+
+        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().getErrorMessage() );
+
+        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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/abandon/AbandonRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/abandon/AbandonRequestTest.java
new file mode 100644
index 0000000..231935b
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/abandon/AbandonRequestTest.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.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.AbandonRequestDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.AbandonRequest;
+import org.apache.directory.shared.ldap.model.message.AbandonRequestImpl;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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.getMessageId() );
+        internalAbandonRequest.setAbandoned( abandonRequest.getAbandoned() );
+
+        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.shared.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.shared.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.shared.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.shared.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.getMessageId() );
+        internalAbandonRequest.setAbandoned( abandonRequest.getAbandoned() );
+
+        // 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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/add/AddRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/add/AddRequestTest.java
new file mode 100644
index 0000000..fadf78f
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/add/AddRequestTest.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.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.model.entry.Value;
+import org.apache.directory.shared.ldap.model.message.*;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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 );
+
+        EntryAttribute attribute = entry.get( "l" );
+
+        assertTrue( expectedTypes.contains( attribute.getId().toLowerCase() ) );
+
+        Set<String> vals = ( Set<String> ) typesVals.get( attribute.getId().toLowerCase() );
+
+        for ( Value<?> value : attribute )
+        {
+            assertTrue( vals.contains( value.get() ) );
+
+            vals.remove( value.get() );
+        }
+
+        attribute = entry.get( "attrs" );
+
+        assertTrue( expectedTypes.contains( attribute.getId().toLowerCase() ) );
+
+        vals = ( Set<String> ) typesVals.get( attribute.getId().toLowerCase() );
+
+        for ( Value<?> value : attribute )
+        {
+            assertTrue( vals.contains( value.get() ) );
+
+            vals.remove( value.get() );
+        }
+
+        // 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() );
+
+        EntryAttribute attribute = entry.get( "l" );
+
+        assertEquals( "l", attribute.getId().toLowerCase() );
+
+        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() );
+
+        EntryAttribute attribute = entry.get( "l" );
+
+        assertEquals( "l", attribute.getId().toLowerCase() );
+
+        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.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/add/AddResponseTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/add/AddResponseTest.java
new file mode 100644
index 0000000..70c4de9
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/add/AddResponseTest.java
@@ -0,0 +1,251 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.AddResponseDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.AddResponse;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.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 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().getErrorMessage() );
+
+        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().getErrorMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = addResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestPerfTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestPerfTest.java
new file mode 100644
index 0000000..b746395
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestPerfTest.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.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.BindRequest;
+import org.apache.directory.shared.ldap.model.message.BindRequestImpl;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Ignore;
+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 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.shared.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 name = 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( 1 );
+
+            bindRequest.setSimple( true );
+            bindRequest.setName( name );
+            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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestTest.java
new file mode 100644
index 0000000..4d063c1
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestTest.java
@@ -0,0 +1,1362 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.BindRequest;
+import org.apache.directory.shared.ldap.model.message.BindResponseImpl;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.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().toString() );
+        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().toString() );
+        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().toString() );
+        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().toString() );
+        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().toString() );
+        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().toString() );
+        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().toString() );
+        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().toString() );
+        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.shared.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().toString() );
+        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.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindResponseTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindResponseTest.java
new file mode 100644
index 0000000..d020381
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindResponseTest.java
@@ -0,0 +1,496 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.controls.search.pagedSearch.PagedResultsDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.BindResponseDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.BindResponse;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.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 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().getErrorMessage() );
+
+        // 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().getErrorMessage() );
+
+        // 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().getErrorMessage() );
+        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().getErrorMessage() );
+        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.shared.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().getErrorMessage() );
+        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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareRequestTest.java
new file mode 100644
index 0000000..3696fd2
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareRequestTest.java
@@ -0,0 +1,515 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.model.message.CompareRequest;
+import org.apache.directory.shared.ldap.model.message.CompareResponseImpl;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.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.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareResponseTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareResponseTest.java
new file mode 100644
index 0000000..3853e62
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareResponseTest.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.shared.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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.CompareResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.CompareResponse;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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().getErrorMessage() );
+
+        // 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().getErrorMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = compareResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/controls/OpaqueControlTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/controls/OpaqueControlTest.java
similarity index 100%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/controls/OpaqueControlTest.java
rename to ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/controls/OpaqueControlTest.java
diff --git a/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/del/DelRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/del/DelRequestTest.java
new file mode 100644
index 0000000..36165b1
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/del/DelRequestTest.java
@@ -0,0 +1,285 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.DeleteRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.*;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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( 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.shared.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( 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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/del/DelResponseTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/del/DelResponseTest.java
new file mode 100644
index 0000000..c8b77d9
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/del/DelResponseTest.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.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.DeleteResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.DeleteResponse;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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().getErrorMessage() );
+
+        // 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().getErrorMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = delResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedRequestTest.java
new file mode 100644
index 0000000..875edfe
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedRequestTest.java
@@ -0,0 +1,521 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.ExtendedRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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
+        ExtendedRequest 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
+        ExtendedRequest 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.shared.ldap.codec.api.CodecControl<Control> ) extendedRequest.getControl( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) 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
+        ExtendedRequest 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.shared.ldap.codec.api.CodecControl<Control> ) extendedRequest.getControl( "2.16.840.1.113730.3.4.2" );
+        assertEquals( "", Strings.dumpBytes( ( byte[] ) 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
+        ExtendedRequest 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
+        ExtendedRequest 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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedResponseTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedResponseTest.java
new file mode 100644
index 0000000..0d5f823
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedResponseTest.java
@@ -0,0 +1,874 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.ExtendedResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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
+        ExtendedResponse extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( "", extendedResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", extendedResponse.getLdapResult().getErrorMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getID() );
+        assertEquals( "value", Strings.utf8ToString((byte[]) extendedResponse.getEncodedValue()) );
+
+        // 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
+        ExtendedResponse extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( "", extendedResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", extendedResponse.getLdapResult().getErrorMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getID() );
+        assertEquals( "value", Strings.utf8ToString((byte[]) extendedResponse.getEncodedValue()) );
+
+        // Check the Control
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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( 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().getErrorMessage() );
+
+        // 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().getErrorMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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( 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
+        ExtendedResponse extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( "", extendedResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", extendedResponse.getLdapResult().getErrorMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getID() );
+        assertEquals( "", Strings.utf8ToString((byte[]) extendedResponse.getEncodedValue()) );
+
+        // 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
+        ExtendedResponse extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( "", extendedResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", extendedResponse.getLdapResult().getErrorMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getID() );
+        assertEquals( "", Strings.utf8ToString((byte[]) extendedResponse.getEncodedValue()) );
+
+        // Check the Control
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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( 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
+        ExtendedResponse extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( "", extendedResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", extendedResponse.getLdapResult().getErrorMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getID() );
+        assertEquals( "", Strings.utf8ToString((byte[]) extendedResponse.getEncodedValue()) );
+
+        // 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
+        ExtendedResponse extendedResponse = container.getMessage();
+
+        assertEquals( 1, extendedResponse.getMessageId() );
+        assertEquals( ResultCodeEnum.SUCCESS, extendedResponse.getLdapResult().getResultCode() );
+        assertEquals( "", extendedResponse.getLdapResult().getMatchedDn().getName() );
+        assertEquals( "", extendedResponse.getLdapResult().getErrorMessage() );
+        assertEquals( "1.3.6.1.5.5.2", extendedResponse.getID() );
+        assertEquals( "", Strings.utf8ToString((byte[]) extendedResponse.getEncodedValue()) );
+
+        // Check the Control
+        Map<String, Control> controls = extendedResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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( 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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/intermediate/IntermediateResponseTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/intermediate/IntermediateResponseTest.java
new file mode 100644
index 0000000..51b669b
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/intermediate/IntermediateResponseTest.java
@@ -0,0 +1,645 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.IntermediateResponse;
+import org.apache.directory.shared.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.shared.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.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyRequestTest.java
new file mode 100644
index 0000000..a54fb93
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyRequestTest.java
@@ -0,0 +1,1307 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.model.entry.Modification;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.ModifyRequest;
+import org.apache.directory.shared.ldap.model.message.ModifyResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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 )
+        {
+            EntryAttribute attribute = modification.getAttribute();
+
+            if ( "l".equalsIgnoreCase( attribute.getId() ) )
+            {
+                String attrValue = attribute.getString();
+                assertEquals( "Paris", attrValue );
+            }
+            else if ( "attrs".equalsIgnoreCase( attribute.getId() ) )
+            {
+                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];
+        EntryAttribute attributeValue = modification.getAttribute();
+
+        assertEquals( "telephonenumber", attributeValue.getId().toLowerCase() );
+
+        String attrValue = attributeValue.getString();
+        assertEquals( "1234567890", attrValue );
+
+        modification = ( Modification ) modifications[1];
+        attributeValue = modification.getAttribute();
+
+        assertEquals( "cn", attributeValue.getId().toLowerCase() );
+
+        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];
+        EntryAttribute attributeValue = modification.getAttribute();
+
+        assertEquals( "description", attributeValue.getId().toLowerCase() );
+        assertEquals( 0, attributeValue.size() );
+
+        modification = ( Modification ) modifications[1];
+        attributeValue = modification.getAttribute();
+
+        String attrValue = attributeValue.getString();
+
+        assertEquals( "telephonenumber", attributeValue.getId().toLowerCase() );
+
+        assertEquals( "01234567890", attrValue );
+
+        modification = ( Modification ) modifications[2];
+        attributeValue = modification.getAttribute();
+
+        attrValue = attributeValue.getString();
+
+        assertEquals( "telephonenumber", attributeValue.getId().toLowerCase() );
+
+        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];
+        EntryAttribute attributeValue = modification.getAttribute();
+
+        assertEquals( "l", attributeValue.getId().toLowerCase() );
+
+        String attrValue = attributeValue.getString();
+        assertEquals( "Paris", attrValue );
+
+        attrValue = attributeValue.get( 1 ).getString();
+        assertEquals( "London", attrValue );
+
+        modification = ( Modification ) modifications[1];
+        attributeValue = modification.getAttribute();
+
+        assertEquals( "attrs", attributeValue.getId().toLowerCase() );
+
+        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];
+        EntryAttribute attributeValue = modification.getAttribute();
+
+        assertEquals( "l", attributeValue.getId().toLowerCase() );
+        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];
+        EntryAttribute attributeValue = modification.getAttribute();
+
+        assertEquals( "l", attributeValue.getId().toLowerCase() );
+        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.shared.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];
+        EntryAttribute attributeValue = modification.getAttribute();
+
+        assertEquals( "l", attributeValue.getId().toLowerCase() );
+        assertEquals( 2, attributeValue.size() );
+
+        String attrValue = attributeValue.getString();
+        assertEquals( "a", attrValue );
+
+        attrValue = attributeValue.get( 1 ).getString();
+        assertEquals( "b", attrValue );
+
+        // 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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyResponseTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyResponseTest.java
new file mode 100644
index 0000000..3bd4de9
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyResponseTest.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.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.ModifyResponse;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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().getErrorMessage() );
+
+        // 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().getErrorMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = modifyResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNRequestTest.java
new file mode 100644
index 0000000..3bf3be8
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNRequestTest.java
@@ -0,0 +1,705 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.shared.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.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.shared.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.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNResponseTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNResponseTest.java
new file mode 100644
index 0000000..0891007
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNResponseTest.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.shared.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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyDnResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.ModifyDnResponse;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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().getErrorMessage() );
+
+        // 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().getErrorMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = modifyDnResponse.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/osgi/AbstractCodecServiceTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/osgi/AbstractCodecServiceTest.java
new file mode 100644
index 0000000..aeda4e4
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/osgi/AbstractCodecServiceTest.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.shared.ldap.codec.osgi;
+
+
+import org.apache.directory.shared.ldap.codec.LdapEncoder;
+import org.apache.directory.shared.ldap.codec.standalone.StandaloneLdapCodecService;
+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 StandaloneLdapCodecService codec;
+
+    /** The encoder instance */
+    protected static LdapEncoder encoder;
+
+    
+    /**
+     * Initialize the codec service
+     */
+    @BeforeClass
+    public static void setupLdapCodecService()
+    {
+        codec = new StandaloneLdapCodecService();
+        encoder = new LdapEncoder( codec );
+    }
+
+
+    /**
+     * Shutdown the codec service
+     */
+    @AfterClass
+    public static void tearDownLdapCodecService()
+    {
+        codec.shutdown();
+        codec = null;
+        encoder = null;
+    }
+}
diff --git a/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java
new file mode 100644
index 0000000..bd8aedb
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java
@@ -0,0 +1,732 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.ExtensibleNode;
+import org.apache.directory.shared.ldap.model.filter.SearchScope;
+import org.apache.directory.shared.ldap.model.message.AliasDerefMode;
+import org.apache.directory.shared.ldap.model.message.SearchRequest;
+import org.apache.directory.shared.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.shared.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.shared.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().get() );
+        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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestSubstringTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestSubstringTest.java
new file mode 100644
index 0000000..fe135ab
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestSubstringTest.java
@@ -0,0 +1,1955 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.SearchScope;
+import org.apache.directory.shared.ldap.model.filter.SubstringNode;
+import org.apache.directory.shared.ldap.model.message.AliasDerefMode;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.SearchRequest;
+import org.apache.directory.shared.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.shared.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.shared.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.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestTest.java
new file mode 100644
index 0000000..dc1c284
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestTest.java
@@ -0,0 +1,4811 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.controls.search.subentries.SubentriesDecorator;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.model.filter.AndNode;
+import org.apache.directory.shared.ldap.model.filter.ApproximateNode;
+import org.apache.directory.shared.ldap.model.filter.EqualityNode;
+import org.apache.directory.shared.ldap.model.filter.ExprNode;
+import org.apache.directory.shared.ldap.model.filter.GreaterEqNode;
+import org.apache.directory.shared.ldap.model.filter.LessEqNode;
+import org.apache.directory.shared.ldap.model.filter.NotNode;
+import org.apache.directory.shared.ldap.model.filter.OrNode;
+import org.apache.directory.shared.ldap.model.filter.PresenceNode;
+import org.apache.directory.shared.ldap.model.filter.SearchScope;
+import org.apache.directory.shared.ldap.model.filter.SubstringNode;
+import org.apache.directory.shared.ldap.model.message.AliasDerefMode;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.message.SearchRequest;
+import org.apache.directory.shared.ldap.model.message.SearchResultDoneImpl;
+import org.apache.directory.shared.ldap.model.message.controls.Subentries;
+import org.apache.directory.shared.ldap.model.schema.normalizers.DeepTrimToLowerNormalizer;
+import org.apache.directory.shared.ldap.model.schema.normalizers.OidNormalizer;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Before;
+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 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( ( ( Subentries ) ( ( 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, // BasDN '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() );
+    }
+}
diff --git a/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultDoneTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultDoneTest.java
new file mode 100644
index 0000000..81e439c
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultDoneTest.java
@@ -0,0 +1,251 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.SearchResultDoneDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.message.SearchResultDone;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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().getErrorMessage() );
+
+        // 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().getErrorMessage() );
+
+        // Check the Control
+        Map<String, Control> controls = searchResultDone.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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" );
+    }
+}
diff --git a/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultEntryTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultEntryTest.java
new file mode 100644
index 0000000..cb2316e
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultEntryTest.java
@@ -0,0 +1,1241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.SearchResultEntry;
+import org.apache.directory.shared.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+/**
+ * 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++ )
+        {
+            EntryAttribute attribute = entry.get( "objectclass" );
+
+            assertEquals( "objectClass".toLowerCase(), attribute.getId().toLowerCase() );
+
+            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++ )
+        {
+            EntryAttribute attribute = entry.get( expectedAttributes[i] );
+
+            assertEquals( expectedAttributes[i].toLowerCase(), attribute.getId().toLowerCase() );
+
+            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++ )
+        {
+            EntryAttribute attribute = entry.get( "objectclass" );
+
+            assertEquals( "objectClass".toLowerCase(), attribute.getId().toLowerCase() );
+
+            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++ )
+        {
+            EntryAttribute attribute = entry.get( "objectclass" );
+
+            assertEquals( "objectClass".toLowerCase(), attribute.getId().toLowerCase() );
+            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() );
+
+        EntryAttribute attribute = entry.get( "objectclass" );
+        assertEquals( "objectClass".toLowerCase(), attribute.getId().toLowerCase() );
+        assertEquals( 0, attribute.size() );
+
+        attribute = entry.get( "objectclazz" );
+        assertEquals( "objectClazz".toLowerCase(), attribute.getId().toLowerCase() );
+        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++ )
+        {
+            EntryAttribute attribute = entry.get( "objectclass" );
+
+            assertEquals( "objectClass".toLowerCase(), attribute.getId().toLowerCase() );
+
+            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.shared.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++ )
+        {
+            EntryAttribute attribute = entry.get( "objectclass" );
+
+            assertEquals( "objectClass".toLowerCase(), attribute.getId().toLowerCase() );
+
+            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++ )
+        {
+            EntryAttribute attribute = entry.get( "objectclass" );
+
+            assertEquals( "objectClass".toLowerCase(), attribute.getId().toLowerCase() );
+
+            assertTrue( attribute.contains( "" ) );
+        }
+
+        // Check the Control
+        Map<String, Control> controls = searchResultEntry.getControls();
+
+        assertEquals( 1, controls.size() );
+
+        @SuppressWarnings("unchecked")
+        CodecControl<Control> control = (org.apache.directory.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultReferenceTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultReferenceTest.java
new file mode 100644
index 0000000..80525c1
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultReferenceTest.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.shared.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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.SearchResultReferenceDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Referral;
+import org.apache.directory.shared.ldap.model.message.SearchResultReference;
+import org.apache.directory.shared.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.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/EntryChangeControlTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/EntryChangeControlTest.java
new file mode 100644
index 0000000..90162e9
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/EntryChangeControlTest.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.shared.ldap.codec.search.controls;
+
+
+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.shared.asn1.DecoderException;
+import org.apache.directory.shared.ldap.codec.controls.search.entryChange.EntryChangeDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.controls.ChangeType;
+import org.apache.directory.shared.ldap.model.message.controls.EntryChange;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PSearchControlTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PSearchControlTest.java
new file mode 100644
index 0000000..79172f4
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PSearchControlTest.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.shared.ldap.codec.search.controls;
+
+
+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.shared.asn1.DecoderException;
+import org.apache.directory.shared.ldap.codec.controls.search.persistentSearch.PersistentSearchDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.controls.ChangeType;
+import org.apache.directory.shared.ldap.model.message.controls.PersistentSearch;
+import org.apache.directory.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PagedSearchControlTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PagedSearchControlTest.java
new file mode 100644
index 0000000..cdc2073
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PagedSearchControlTest.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.shared.ldap.codec.search.controls;
+
+
+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.shared.asn1.DecoderException;
+import org.apache.directory.shared.ldap.codec.controls.search.pagedSearch.PagedResultsDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.controls.PagedResults;
+import org.apache.directory.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/SubEntryControlTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/SubEntryControlTest.java
new file mode 100644
index 0000000..a180bdc
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/SubEntryControlTest.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.shared.ldap.codec.search.controls;
+
+
+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.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.ldap.codec.controls.search.subentries.SubentriesDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.controls.Subentries;
+import org.apache.directory.shared.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/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/unbind/UnBindRequestTest.java b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/unbind/UnBindRequestTest.java
new file mode 100644
index 0000000..b8e6e9d
--- /dev/null
+++ b/ldap-codec-standalone/src/test/java/org/apache/directory/shared/ldap/codec/unbind/UnBindRequestTest.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.shared.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 com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.decorators.UnbindRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.UnbindRequest;
+import org.apache.directory.shared.ldap.model.message.UnbindRequestImpl;
+import org.apache.directory.shared.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 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( 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.shared.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( 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/ldap/src/test/resources/log4j.properties b/ldap-codec-standalone/src/test/resources/log4j.properties
similarity index 100%
copy from ldap/src/test/resources/log4j.properties
copy to ldap-codec-standalone/src/test/resources/log4j.properties
diff --git a/ldap-codec/pom.xml b/ldap-codec/pom.xml
index 3613145..dc6d3af 100644
--- a/ldap-codec/pom.xml
+++ b/ldap-codec/pom.xml
@@ -76,6 +76,12 @@
       <groupId>commons-collections</groupId>
       <artifactId>commons-collections</artifactId>
     </dependency>
+    
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi</artifactId>
+      <scope>provided</scope>
+    </dependency>
   </dependencies>
 
   <build>
@@ -94,16 +100,6 @@
       </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>
@@ -123,11 +119,13 @@
           <manifestLocation>META-INF</manifestLocation>
           <instructions>
             <Bundle-SymbolicName>${project.groupId}.ldap.codec</Bundle-SymbolicName>
+            <Bundle-ActivationPolicy>lazy</Bundle-ActivationPolicy>
             <Export-Package>
-              org.apache.directory.shared.ldap.codec.api,
-              org.apache.directory.shared.ldap.extras.controls,
-              org.apache.directory.shared.ldap.extras.extended
+              org.apache.directory.shared.ldap.codec.api
             </Export-Package>
+            <Bundle-Activator>
+              org.apache.directory.shared.ldap.codec.osgi.DefaultActivator
+            </Bundle-Activator>
           </instructions>
         </configuration>
       </plugin>
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/BasicControlDecorator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/BasicControlDecorator.java
index b31a1ee..c9e5c1d 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/BasicControlDecorator.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/BasicControlDecorator.java
@@ -26,9 +26,9 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.codec.api.ControlFactory;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.controls.AbstractControl;
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapDecoder.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapDecoder.java
index 04ddb42..a0aa4f6 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapDecoder.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapDecoder.java
@@ -6,24 +6,24 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.ldap.codec;
 
 
 import java.io.InputStream;
 import java.nio.ByteBuffer;
+import java.security.ProviderException;
 
-import org.apache.directory.shared.asn1.DecoderCallback;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
@@ -43,7 +43,7 @@
 
 /**
  * The LdapDecoder decodes ASN.1 BER encoded PDUs.
- * 
+ *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 public class LdapDecoder implements ProtocolDecoder
@@ -57,9 +57,6 @@
     /** The message container for this instance */
     private LdapMessageContainer<MessageDecorator<? extends Message>> ldapMessageContainer;
 
-    /** The callback to call when the decoding is done */
-    private DecoderCallback decoderCallback;
-
     /** The ASN 1 decoder instance */
     private Asn1Decoder asn1Decoder;
 
@@ -76,7 +73,7 @@
     /**
      * Feeds the bytes within the input stream to the digester to generate the
      * resultant decoded Message.
-     * 
+     *
      * @param in The InputStream containing the PDU to be decoded
      * @throws ProviderException If the decoding went wrong
      */
@@ -112,7 +109,7 @@
     /**
      * Decodes a PDU from an input stream into a Snickers compiler generated
      * stub envelope.
-     * 
+     *
      * @param lock Lock object used to exclusively read from the input stream
      * @param in The input stream to read and decode PDU bytes from
      * @return return decoded stub
@@ -177,31 +174,11 @@
     }
 
 
-    /**
-     * Set the callback to call when the PDU has been decoded
-     * 
-     * @param cb The callback
-     */
-    public void setCallback( DecoderCallback cb )
-    {
-        decoderCallback = cb;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public DecoderCallback getCallback()
-    {
-        return decoderCallback;
-    }
-
-
     @SuppressWarnings("unchecked")
     public void decode( IoSession session, IoBuffer in, ProtocolDecoderOutput out ) throws Exception
     {
         ByteBuffer buf = in.buf();
-        LdapMessageContainer<MessageDecorator<? extends Message>> messageContainer = 
+        LdapMessageContainer<MessageDecorator<? extends Message>> messageContainer =
             ( LdapMessageContainer<MessageDecorator<? extends Message>> ) session.getAttribute( "messageContainer" );
 
         if ( session.containsAttribute( "maxPDUSize" ) )
@@ -252,9 +229,9 @@
                     {
                         LOG.debug( "Decoded LdapMessage : " + messageContainer.getMessage() );
                     }
-                    
+
                     Message message = messageContainer.getMessage();
-                    
+
                     out.write( message );
 
                     messageContainer.clean();
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapEncoder.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapEncoder.java
index c819981..ac6ec5a 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapEncoder.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapEncoder.java
@@ -31,7 +31,6 @@
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.LdapConstants;
 import org.apache.directory.shared.ldap.codec.api.MessageEncoderException;
@@ -50,9 +49,14 @@
 public class LdapEncoder
 {
     /** The LdapCodecService */
-    private LdapCodecService codec = new DefaultLdapCodecService();
+    private LdapCodecService codec;
     
     
+    public LdapEncoder( LdapCodecService codec )
+    {
+        this.codec = codec;
+    }
+    
     
     private int computeControlLength( Control control )
     {
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapMessageContainer.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapMessageContainer.java
index 46d8534..f51f84b 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapMessageContainer.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapMessageContainer.java
@@ -23,7 +23,7 @@
 import org.apache.directory.shared.asn1.ber.AbstractContainer;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
 import org.apache.directory.shared.ldap.codec.api.BinaryAttributeDetector;
 import org.apache.directory.shared.ldap.model.message.Control;
@@ -34,7 +34,7 @@
  * 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
@@ -50,7 +50,7 @@
 
     /** The current control */
     private ControlDecorator<? extends Control> currentControl;
-    
+
     /** The codec service */
     private final LdapCodecService codec;
 
@@ -97,8 +97,8 @@
     {
         return codec;
     }
-    
-    
+
+
     /**
      * @return Returns the ldapMessage.
      */
@@ -111,7 +111,7 @@
     /**
      * 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 )
@@ -123,6 +123,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public void clean()
     {
         super.clean();
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapMessageGrammar.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapMessageGrammar.java
index 7b03bdc..f394776 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapMessageGrammar.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapMessageGrammar.java
@@ -6,137 +6,133 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.ldap.codec;
 
 
+import static org.apache.directory.shared.asn1.ber.tlv.UniversalTag.BOOLEAN;
+import static org.apache.directory.shared.asn1.ber.tlv.UniversalTag.ENUMERATED;
+import static org.apache.directory.shared.asn1.ber.tlv.UniversalTag.INTEGER;
+import static org.apache.directory.shared.asn1.ber.tlv.UniversalTag.OCTET_STRING;
+import static org.apache.directory.shared.asn1.ber.tlv.UniversalTag.SEQUENCE;
+import static org.apache.directory.shared.asn1.ber.tlv.UniversalTag.SET;
+
 import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.actions.CheckNotNullLength;
 import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
-import org.apache.directory.shared.asn1.ber.grammar.Action;
 import org.apache.directory.shared.asn1.ber.grammar.Grammar;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
-import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoder;
-import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoderException;
-import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
-import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
-import org.apache.directory.shared.asn1.ber.tlv.LongDecoder;
-import org.apache.directory.shared.asn1.ber.tlv.LongDecoderException;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
-import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
-import org.apache.directory.shared.asn1.ber.tlv.Value;
-import org.apache.directory.shared.asn1.util.OID;
 import org.apache.directory.shared.i18n.I18n;
-import org.apache.directory.shared.ldap.codec.actions.AttributeDescAction;
-import org.apache.directory.shared.ldap.codec.actions.ControlValueAction;
-import org.apache.directory.shared.ldap.codec.actions.ControlsInitAction;
-import org.apache.directory.shared.ldap.codec.actions.ErrorMessageAction;
-import org.apache.directory.shared.ldap.codec.actions.InitAndFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitApproxMatchFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitAssertionValueFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitAttributeDescFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitAttributeDescListAction;
-import org.apache.directory.shared.ldap.codec.actions.InitEqualityMatchFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitExtensibleMatchFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitGreaterOrEqualFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitLessOrEqualFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitNotFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitOrFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitPresentFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.InitReferralsAction;
-import org.apache.directory.shared.ldap.codec.actions.InitSubstringsFilterAction;
-import org.apache.directory.shared.ldap.codec.actions.MatchedDNAction;
-import org.apache.directory.shared.ldap.codec.actions.ModifyAttributeValueAction;
-import org.apache.directory.shared.ldap.codec.actions.ReferralAction;
-import org.apache.directory.shared.ldap.codec.actions.ResponseAction;
-import org.apache.directory.shared.ldap.codec.actions.ResponseNameAction;
-import org.apache.directory.shared.ldap.codec.actions.ResultCodeAction;
-import org.apache.directory.shared.ldap.codec.actions.SearchResultAttributeValueAction;
-import org.apache.directory.shared.ldap.codec.actions.ServerSASLCredsAction;
-import org.apache.directory.shared.ldap.codec.actions.StoreAnyAction;
-import org.apache.directory.shared.ldap.codec.actions.StoreFinalAction;
-import org.apache.directory.shared.ldap.codec.actions.StoreMatchValueAction;
-import org.apache.directory.shared.ldap.codec.actions.StoreReferenceAction;
-import org.apache.directory.shared.ldap.codec.actions.StoreTypeMatchingRuleAction;
-import org.apache.directory.shared.ldap.codec.actions.ValueAction;
+import org.apache.directory.shared.ldap.codec.actions.AllowGrammarEnd;
+import org.apache.directory.shared.ldap.codec.actions.CheckLengthNotNull;
+import org.apache.directory.shared.ldap.codec.actions.abandonRequest.InitAbandonRequest;
+import org.apache.directory.shared.ldap.codec.actions.addRequest.AddAddRequestAttributeType;
+import org.apache.directory.shared.ldap.codec.actions.addRequest.AddAttributeValue;
+import org.apache.directory.shared.ldap.codec.actions.addRequest.InitAddRequest;
+import org.apache.directory.shared.ldap.codec.actions.addRequest.StoreAddRequestEntryName;
+import org.apache.directory.shared.ldap.codec.actions.addResponse.InitAddResponse;
+import org.apache.directory.shared.ldap.codec.actions.bindRequest.InitBindRequest;
+import org.apache.directory.shared.ldap.codec.actions.bindRequest.InitSaslBind;
+import org.apache.directory.shared.ldap.codec.actions.bindRequest.StoreName;
+import org.apache.directory.shared.ldap.codec.actions.bindRequest.StoreSaslCredentials;
+import org.apache.directory.shared.ldap.codec.actions.bindRequest.StoreSaslMechanism;
+import org.apache.directory.shared.ldap.codec.actions.bindRequest.StoreSimpleAuth;
+import org.apache.directory.shared.ldap.codec.actions.bindRequest.StoreVersion;
+import org.apache.directory.shared.ldap.codec.actions.bindResponse.InitBindResponse;
+import org.apache.directory.shared.ldap.codec.actions.bindResponse.StoreServerSASLCreds;
+import org.apache.directory.shared.ldap.codec.actions.compareRequest.InitCompareRequest;
+import org.apache.directory.shared.ldap.codec.actions.compareRequest.StoreCompareRequestAssertionValue;
+import org.apache.directory.shared.ldap.codec.actions.compareRequest.StoreCompareRequestAttributeDesc;
+import org.apache.directory.shared.ldap.codec.actions.compareRequest.StoreCompareRequestEntryName;
+import org.apache.directory.shared.ldap.codec.actions.compareResponse.InitCompareResponse;
+import org.apache.directory.shared.ldap.codec.actions.controls.AddControl;
+import org.apache.directory.shared.ldap.codec.actions.controls.InitControls;
+import org.apache.directory.shared.ldap.codec.actions.controls.StoreControlCriticality;
+import org.apache.directory.shared.ldap.codec.actions.controls.StoreControlValue;
+import org.apache.directory.shared.ldap.codec.actions.delRequest.InitDelRequest;
+import org.apache.directory.shared.ldap.codec.actions.delResponse.InitDelResponse;
+import org.apache.directory.shared.ldap.codec.actions.extendedRequest.InitExtendedRequest;
+import org.apache.directory.shared.ldap.codec.actions.extendedRequest.StoreExtendedRequestName;
+import org.apache.directory.shared.ldap.codec.actions.extendedRequest.StoreExtendedRequestValue;
+import org.apache.directory.shared.ldap.codec.actions.extendedResponse.InitExtendedResponse;
+import org.apache.directory.shared.ldap.codec.actions.extendedResponse.StoreExtendedResponseValue;
+import org.apache.directory.shared.ldap.codec.actions.extendedResponse.StoreResponseName;
+import org.apache.directory.shared.ldap.codec.actions.intermediateResponse.InitIntermediateResponse;
+import org.apache.directory.shared.ldap.codec.actions.intermediateResponse.StoreIntermediateResponseName;
+import org.apache.directory.shared.ldap.codec.actions.intermediateResponse.StoreIntermediateResponseValue;
+import org.apache.directory.shared.ldap.codec.actions.ldapMessage.InitLdapMessage;
+import org.apache.directory.shared.ldap.codec.actions.ldapMessage.StoreMessageId;
+import org.apache.directory.shared.ldap.codec.actions.ldapResult.AddReferral;
+import org.apache.directory.shared.ldap.codec.actions.ldapResult.InitReferrals;
+import org.apache.directory.shared.ldap.codec.actions.ldapResult.StoreErrorMessage;
+import org.apache.directory.shared.ldap.codec.actions.ldapResult.StoreMatchedDN;
+import org.apache.directory.shared.ldap.codec.actions.ldapResult.StoreResultCode;
+import org.apache.directory.shared.ldap.codec.actions.modifyDnRequest.InitModifyDnRequest;
+import org.apache.directory.shared.ldap.codec.actions.modifyDnRequest.StoreModifyDnRequestDeleteOldRdn;
+import org.apache.directory.shared.ldap.codec.actions.modifyDnRequest.StoreModifyDnRequestEntryName;
+import org.apache.directory.shared.ldap.codec.actions.modifyDnRequest.StoreModifyDnRequestNewRdn;
+import org.apache.directory.shared.ldap.codec.actions.modifyDnRequest.StoreModifyDnRequestNewSuperior;
+import org.apache.directory.shared.ldap.codec.actions.modifyDnResponse.InitModifyDnResponse;
+import org.apache.directory.shared.ldap.codec.actions.modifyRequest.AddModifyRequestAttribute;
+import org.apache.directory.shared.ldap.codec.actions.modifyRequest.InitAttributeVals;
+import org.apache.directory.shared.ldap.codec.actions.modifyRequest.InitModifyRequest;
+import org.apache.directory.shared.ldap.codec.actions.modifyRequest.StoreModifyRequestAttributeValue;
+import org.apache.directory.shared.ldap.codec.actions.modifyRequest.StoreModifyRequestObjectName;
+import org.apache.directory.shared.ldap.codec.actions.modifyRequest.StoreOperationType;
+import org.apache.directory.shared.ldap.codec.actions.modifyResponse.InitModifyResponse;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.InitSearchRequest;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.InitSearchRequestAttributeDescList;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.StoreSearchRequestAttributeDesc;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.StoreSearchRequestBaseObject;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.StoreSearchRequestDerefAlias;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.StoreSearchRequestScope;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.StoreSearchRequestSizeLimit;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.StoreSearchRequestTimeLimit;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.StoreSearchRequestTypesOnly;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.StoreTypeMatchingRule;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitAndFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitApproxMatchFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitAssertionValueFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitAttributeDescFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitEqualityMatchFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitExtensibleMatchFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitGreaterOrEqualFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitLessOrEqualFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitNotFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitOrFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitPresentFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.InitSubstringsFilter;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.StoreAny;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.StoreFinal;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.StoreInitial;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.StoreMatchValue;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.StoreMatchingRuleDnAttributes;
+import org.apache.directory.shared.ldap.codec.actions.searchRequest.filter.StoreSubstringFilterType;
+import org.apache.directory.shared.ldap.codec.actions.searchResultDone.InitSearchResultDone;
+import org.apache.directory.shared.ldap.codec.actions.searchResultEntry.AddAttributeType;
+import org.apache.directory.shared.ldap.codec.actions.searchResultEntry.InitSearchResultEntry;
+import org.apache.directory.shared.ldap.codec.actions.searchResultEntry.StoreSearchResultAttributeValue;
+import org.apache.directory.shared.ldap.codec.actions.searchResultEntry.StoreSearchResultEntryObjectName;
+import org.apache.directory.shared.ldap.codec.actions.searchResultReference.InitSearchResultReference;
+import org.apache.directory.shared.ldap.codec.actions.searchResultReference.StoreReference;
+import org.apache.directory.shared.ldap.codec.actions.unbindRequest.InitUnbindRequest;
 import org.apache.directory.shared.ldap.codec.api.LdapConstants;
-import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
-import org.apache.directory.shared.ldap.codec.decorators.AbandonRequestDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.AddRequestDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.AddResponseDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.BindResponseDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.CompareRequestDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.CompareResponseDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.DeleteRequestDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.DeleteResponseDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.ExtendedRequestDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.ExtendedResponseDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.IntermediateResponseDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.ModifyDnRequestDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.ModifyDnResponseDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.ModifyRequestDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.ModifyResponseDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.SearchResultDoneDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.SearchResultEntryDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.SearchResultReferenceDecorator;
-import org.apache.directory.shared.ldap.codec.decorators.UnbindRequestDecorator;
 import org.apache.directory.shared.ldap.codec.search.ExtensibleMatchFilter;
-import org.apache.directory.shared.ldap.codec.search.SubstringFilter;
-import org.apache.directory.shared.ldap.model.exception.LdapException;
-import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
-import org.apache.directory.shared.ldap.model.filter.SearchScope;
-import org.apache.directory.shared.ldap.model.message.AbandonRequestImpl;
-import org.apache.directory.shared.ldap.model.message.AddRequestImpl;
-import org.apache.directory.shared.ldap.model.message.AddResponseImpl;
-import org.apache.directory.shared.ldap.model.message.AliasDerefMode;
-import org.apache.directory.shared.ldap.model.message.BindRequest;
-import org.apache.directory.shared.ldap.model.message.BindRequestImpl;
-import org.apache.directory.shared.ldap.model.message.BindResponseImpl;
-import org.apache.directory.shared.ldap.model.message.CompareRequest;
-import org.apache.directory.shared.ldap.model.message.CompareRequestImpl;
-import org.apache.directory.shared.ldap.model.message.CompareResponseImpl;
-import org.apache.directory.shared.ldap.model.message.Control;
-import org.apache.directory.shared.ldap.model.message.DeleteRequestImpl;
-import org.apache.directory.shared.ldap.model.message.DeleteResponseImpl;
-import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
-import org.apache.directory.shared.ldap.model.message.ExtendedRequestImpl;
-import org.apache.directory.shared.ldap.model.message.ExtendedResponseImpl;
-import org.apache.directory.shared.ldap.model.message.IntermediateResponse;
-import org.apache.directory.shared.ldap.model.message.IntermediateResponseImpl;
-import org.apache.directory.shared.ldap.model.message.LdapResult;
 import org.apache.directory.shared.ldap.model.message.Message;
-import org.apache.directory.shared.ldap.model.message.ModifyDnRequest;
-import org.apache.directory.shared.ldap.model.message.ModifyDnRequestImpl;
-import org.apache.directory.shared.ldap.model.message.ModifyDnResponseImpl;
-import org.apache.directory.shared.ldap.model.message.ModifyRequest;
-import org.apache.directory.shared.ldap.model.message.ModifyRequestImpl;
-import org.apache.directory.shared.ldap.model.message.ModifyResponseImpl;
-import org.apache.directory.shared.ldap.model.message.Referral;
-import org.apache.directory.shared.ldap.model.message.ReferralImpl;
-import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
-import org.apache.directory.shared.ldap.model.message.ResultResponse;
-import org.apache.directory.shared.ldap.model.message.SearchRequest;
-import org.apache.directory.shared.ldap.model.message.SearchRequestImpl;
-import org.apache.directory.shared.ldap.model.message.SearchResultDoneImpl;
-import org.apache.directory.shared.ldap.model.message.SearchResultEntryImpl;
-import org.apache.directory.shared.ldap.model.message.SearchResultReferenceImpl;
-import org.apache.directory.shared.ldap.model.message.UnbindRequestImpl;
-import org.apache.directory.shared.ldap.model.name.Dn;
-import org.apache.directory.shared.ldap.model.name.Rdn;
-import org.apache.directory.shared.util.StringConstants;
 import org.apache.directory.shared.util.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -146,14 +142,11 @@
  * 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 extends AbstractGrammar
+public final class LdapMessageGrammar<E> extends AbstractGrammar<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
-    // ~ Static fields/initializers
-    // -----------------------------------------------------------------
-
     /** The logger */
     static final Logger LOG = LoggerFactory.getLogger( LdapMessageGrammar.class );
 
@@ -161,11 +154,8 @@
     static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
     /** The instance of grammar. LdapMessageGrammar is a singleton */
-    private static Grammar instance = new LdapMessageGrammar();
-
-
-    // ~ Constructors
-    // -------------------------------------------------------------------------------
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private static Grammar<LdapMessageContainer<MessageDecorator<? extends Message>>> instance = new LdapMessageGrammar();
 
     /**
      * Creates a new LdapMessageGrammar object.
@@ -183,31 +173,19 @@
         // Transition from START to LdapMessage
         // ============================================================================================
         // This is the starting state :
-        // LDAPMessage --> SEQUENCE { ... 
+        // LDAPMessage --> SEQUENCE { ...
         //
-        // We have a LDAPMessage, and the tag must be 0x30. 
+        // 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()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.START_STATE, LdapStatesEnum.LDAP_MESSAGE_STATE, UniversalTag.SEQUENCE.getValue(),
-            new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "LdapMessage initialization" )
-            {
-                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 ) );
-                    }
-                }
-            } );
+        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
@@ -222,48 +200,12 @@
         //
         // 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()][UniversalTag.INTEGER.getValue()] = new GrammarTransition(
-            LdapStatesEnum.LDAP_MESSAGE_STATE, LdapStatesEnum.MESSAGE_ID_STATE, UniversalTag.INTEGER.getValue(),
-            new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Store MessageId" )
-            {
-                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 ) );
-                    }
-
-                    Value 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() );
-                    }
-                }
-            } );
+        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 :
@@ -296,34 +238,12 @@
         // --------------------------------------------------------------------------------------------
         // LdapMessage ::= ... UnBindRequest ...
         // unbindRequest ::= [APPLICATION 2] NULL
-        // We have to switch to the UnBindRequest grammar
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.UNBIND_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.UNBIND_REQUEST_STATE, LdapConstants.UNBIND_REQUEST_TAG,
-            new GrammarAction<LdapMessageContainer<UnbindRequestDecorator>>( "Unbind Request initialization" )
-            {
-                public void action( LdapMessageContainer<UnbindRequestDecorator> container ) throws DecoderException
-                {
-                    // Create the UnbindRequest LdapMessage instance and store it in the container
-                    UnbindRequestDecorator unbindRequest = new UnbindRequestDecorator( 
-                        container.getLdapCodecService(), new UnbindRequestImpl( container.getMessageId() ) );
-                    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 );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.UNBIND_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.UNBIND_REQUEST_STATE,
+                LdapConstants.UNBIND_REQUEST_TAG,
+                new InitUnbindRequest() );
 
         // --------------------------------------------------------------------------------------------
         // transition from UnBindRequest Message to Controls.
@@ -332,9 +252,12 @@
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        super.transitions[LdapStatesEnum.UNBIND_REQUEST_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.UNBIND_REQUEST_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.UNBIND_REQUEST_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.UNBIND_REQUEST_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Message ID to DelRequest Message.
@@ -343,62 +266,12 @@
         // delRequest ::= [APPLICATION 10] LDAPDN
         //
         // We store the Dn to bve deleted into the DelRequest object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.DEL_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.DEL_REQUEST_STATE, LdapConstants.DEL_REQUEST_TAG,
-            new GrammarAction<LdapMessageContainer<DeleteRequestDecorator>>( "Init del Request" )
-            {
-                public void action( LdapMessageContainer<DeleteRequestDecorator> container ) throws DecoderException
-                {
-                    // Create the DeleteRequest LdapMessage instance and store it in the container
-                    DeleteRequestDecorator delRequest = new DeleteRequestDecorator( 
-                        container.getLdapCodecService(), new DeleteRequestImpl( container.getMessageId() ) );
-                    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 );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.DEL_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.DEL_REQUEST_STATE,
+                LdapConstants.DEL_REQUEST_TAG,
+                new InitDelRequest() );
 
         // --------------------------------------------------------------------------------------------
         // transition from DelRequest Message to Controls.
@@ -407,9 +280,12 @@
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        super.transitions[LdapStatesEnum.DEL_REQUEST_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.DEL_REQUEST_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.DEL_REQUEST_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DEL_REQUEST_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Message ID to AbandonRequest Message.
@@ -418,59 +294,12 @@
         // AbandonRequest ::= [APPLICATION 16] MessageID
         //
         // Create the AbandonRequest object, and store the ID in it
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.ABANDON_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.ABANDON_REQUEST_STATE, LdapConstants.ABANDON_REQUEST_TAG,
-            new GrammarAction<LdapMessageContainer<AbandonRequestDecorator>>( "Init Abandon Request" )
-            {
-                public void action( LdapMessageContainer<AbandonRequestDecorator> container ) throws DecoderException
-                {
-                    // Create the AbandonRequest LdapMessage instance and store it in the container
-                    AbandonRequestDecorator abandonRequest = new AbandonRequestDecorator( 
-                        container.getLdapCodecService(), new AbandonRequestImpl( container.getMessageId() ) );
-                    container.setMessage( abandonRequest );
-
-                    // The current TLV should be a integer
-                    // We get it and store it in MessageId
-                    TLV tlv = container.getCurrentTLV();
-
-                    Value 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() );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.ABANDON_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.ABANDON_REQUEST_STATE,
+                LdapConstants.ABANDON_REQUEST_TAG,
+                new InitAbandonRequest() );
 
         // --------------------------------------------------------------------------------------------
         // transition from AbandonRequest Message to Controls.
@@ -479,9 +308,12 @@
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        super.transitions[LdapStatesEnum.ABANDON_REQUEST_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ABANDON_REQUEST_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.ABANDON_REQUEST_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ABANDON_REQUEST_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Message ID to BindRequest Message.
@@ -490,30 +322,12 @@
         // BindRequest ::= [APPLICATION 0] SEQUENCE { ...
         //
         // We have to allocate a BindRequest
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.BIND_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.BIND_REQUEST_STATE, LdapConstants.BIND_REQUEST_TAG,
-            new GrammarAction<LdapMessageContainer<BindRequestDecorator>>( "Init BindRequest" )
-            {
-                public void action( LdapMessageContainer<BindRequestDecorator> container ) throws DecoderException
-                {
-                    // Create the BindRequest LdapMessage instance and store it in the container
-                    BindRequestDecorator bindRequest = new BindRequestDecorator( 
-                        container.getLdapCodecService(), new BindRequestImpl( container.getMessageId() ) );
-                    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 );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.BIND_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.BIND_REQUEST_STATE,
+                LdapConstants.BIND_REQUEST_TAG,
+                new InitBindRequest() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from BindRequest to version
@@ -523,41 +337,12 @@
         //     ....
         //
         // The Ldap version is parsed and stored into the BindRequest object
-        super.transitions[LdapStatesEnum.BIND_REQUEST_STATE.ordinal()][UniversalTag.INTEGER.getValue()] = new GrammarTransition(
-            LdapStatesEnum.BIND_REQUEST_STATE, LdapStatesEnum.VERSION_STATE, UniversalTag.INTEGER.getValue(),
-            new GrammarAction<LdapMessageContainer<BindRequestDecorator>>( "Store version" )
-            {
-                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();
-
-                    Value 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() );
-                    }
-                }
-            } );
+        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
@@ -567,52 +352,13 @@
         //     name                    LDAPDN,
         //     ....
         //
-        // The Ldap version is parsed and stored into the BindRequest object
-        super.transitions[LdapStatesEnum.VERSION_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.VERSION_STATE, LdapStatesEnum.NAME_STATE, UniversalTag.OCTET_STRING.getValue(), 
-            new GrammarAction<LdapMessageContainer<BindRequestDecorator>>( "Store Bind Name value" )
-            {
-                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( Dn.EMPTY_DN );
-                    }
-                    else
-                    {
-                        byte[] dnBytes = tlv.getValue().getData();
-                        String dnStr = Strings.utf8ToString(dnBytes);
-
-                        try
-                        {
-                            Dn dn = new Dn( dnStr );
-                            bindRequestMessage.setName( dn );
-                        }
-                        catch ( LdapInvalidDnException ine )
-                        {
-                            String msg = "Incorrect Dn given : " + dnStr + " (" + Strings.dumpBytes(dnBytes)
-                                + ") 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() );
-                    }
-                }
-            } );
+        // 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
@@ -626,38 +372,12 @@
         //     ...
         //
         // We have to create an Authentication Object to store the credentials.
-        super.transitions[LdapStatesEnum.NAME_STATE.ordinal()][LdapConstants.BIND_REQUEST_SIMPLE_TAG] = new GrammarTransition(
-            LdapStatesEnum.NAME_STATE, LdapStatesEnum.SIMPLE_STATE, LdapConstants.BIND_REQUEST_SIMPLE_TAG,
-            new GrammarAction<LdapMessageContainer<BindRequestDecorator>>( "Store Bind Simple Authentication value" )
-            {
-                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()) );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.NAME_STATE.ordinal()][LdapConstants.BIND_REQUEST_SIMPLE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NAME_STATE,
+                LdapStatesEnum.SIMPLE_STATE,
+                LdapConstants.BIND_REQUEST_SIMPLE_TAG,
+                new StoreSimpleAuth() );
 
         // --------------------------------------------------------------------------------------------
         // transition from Simple Authentication to Controls.
@@ -666,9 +386,12 @@
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        super.transitions[LdapStatesEnum.SIMPLE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.SIMPLE_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.SIMPLE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SIMPLE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from name to SASL Authentication
@@ -683,35 +406,12 @@
         //     ...
         //
         // We have to create an Authentication Object to store the credentials.
-        super.transitions[LdapStatesEnum.NAME_STATE.ordinal()][LdapConstants.BIND_REQUEST_SASL_TAG] = new GrammarTransition(
-            LdapStatesEnum.NAME_STATE, LdapStatesEnum.SASL_STATE, LdapConstants.BIND_REQUEST_SASL_TAG,
-            new GrammarAction<LdapMessageContainer<BindRequestDecorator>>( "Initialize Bind SASL Authentication" )
-            {
-                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.getName(), null );
-                    }
-
-                    bindRequestMessage.setSimple( false );
-
-                    if ( IS_DEBUG )
-                    {
-                        LOG.debug( "The SaslCredential has been created" );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.NAME_STATE.ordinal()][LdapConstants.BIND_REQUEST_SASL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NAME_STATE,
+                LdapStatesEnum.SASL_STATE,
+                LdapConstants.BIND_REQUEST_SASL_TAG,
+                new InitSaslBind() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from SASL Authentication to Mechanism
@@ -721,35 +421,12 @@
         //     ...
         //
         // We have to store the mechanism.
-        super.transitions[LdapStatesEnum.SASL_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.SASL_STATE, LdapStatesEnum.MECHANISM_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<BindRequestDecorator>>( "Store SASL mechanism" )
-            {
-                public void action( LdapMessageContainer<BindRequestDecorator> container ) throws DecoderException
-                {
-                    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() );
-                    }
-                }
-            } );
+        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
@@ -759,38 +436,12 @@
         //     credentials OCTET STRING OPTIONAL }
         //
         // We have to store the mechanism.
-        super.transitions[LdapStatesEnum.MECHANISM_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MECHANISM_STATE, LdapStatesEnum.CREDENTIALS_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<BindRequestDecorator>>( "Store SASL credentials" )
-            {
-                public void action( LdapMessageContainer<BindRequestDecorator> container )
-                {
-                    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()) );
-                    }
-                }
-            } );
+        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.
@@ -799,9 +450,12 @@
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        super.transitions[LdapStatesEnum.MECHANISM_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.MECHANISM_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.MECHANISM_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MECHANISM_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // transition from credentials to Controls.
@@ -810,44 +464,44 @@
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        super.transitions[LdapStatesEnum.CREDENTIALS_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.CREDENTIALS_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.CREDENTIALS_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.CREDENTIALS_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from MessageId to BindResponse message 
+        // 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()][LdapConstants.BIND_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.BIND_RESPONSE_STATE, LdapConstants.BIND_RESPONSE_TAG,
-            new GrammarAction<LdapMessageContainer<BindResponseDecorator>>( "Init BindReponse" )
-            {
-                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 );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.BIND_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.BIND_RESPONSE_STATE,
+                LdapConstants.BIND_RESPONSE_TAG,
+                new InitBindResponse() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from BindResponse message to Result Code BR 
+        // Transition from BindResponse message to Result Code BR
         // --------------------------------------------------------------------------------------------
         // BindResponse ::= [APPLICATION 1] SEQUENCE {
         //     COMPONENTS OF LDAPResult,
         //     ...
         //
         // LDAPResult ::= SEQUENCE {
-        //     resultCode ENUMERATED { 
+        //     resultCode ENUMERATED {
         //         ...
-        // 
+        //
         // Stores the result code into the Bind Response object
-        super.transitions[LdapStatesEnum.BIND_RESPONSE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.BIND_RESPONSE_STATE, LdapStatesEnum.RESULT_CODE_BR_STATE, UniversalTag.ENUMERATED.getValue(),
-            new ResultCodeAction() );
+        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
@@ -858,9 +512,12 @@
         //     ...
         //
         // Stores the matched Dn
-        super.transitions[LdapStatesEnum.RESULT_CODE_BR_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.RESULT_CODE_BR_STATE, LdapStatesEnum.MATCHED_DN_BR_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new MatchedDNAction() );
+        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
@@ -871,101 +528,128 @@
         //     ...
         //
         // Stores the error message
-        super.transitions[LdapStatesEnum.MATCHED_DN_BR_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MATCHED_DN_BR_STATE, LdapStatesEnum.ERROR_MESSAGE_BR_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ErrorMessageAction() );
+        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 
+        // 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()][LdapConstants.SERVER_SASL_CREDENTIAL_TAG] = new GrammarTransition(
-            LdapStatesEnum.ERROR_MESSAGE_BR_STATE, LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE,
-            LdapConstants.SERVER_SASL_CREDENTIAL_TAG, new ServerSASLCredsAction() );
+        // Stores the sasl credentials
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_BR_STATE.ordinal()][LdapConstants.SERVER_SASL_CREDENTIAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_BR_STATE,
+                LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE,
+                LdapConstants.SERVER_SASL_CREDENTIAL_TAG,
+                new StoreServerSASLCreds() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Error Message BR to Referrals BR 
+        // 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()][LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG] = new GrammarTransition(
-            LdapStatesEnum.ERROR_MESSAGE_BR_STATE, LdapStatesEnum.REFERRALS_BR_STATE,
-            LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG, new InitReferralsAction() );
+        // Initialiaze the referrals list
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_BR_STATE.ordinal()][LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_BR_STATE,
+                LdapStatesEnum.REFERRALS_BR_STATE,
+                LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG,
+                new InitReferrals() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Referrals BR to Referral BR 
+        // 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()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.REFERRALS_BR_STATE, LdapStatesEnum.REFERRAL_BR_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ReferralAction() );
+        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 
+        // 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()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.REFERRAL_BR_STATE, LdapStatesEnum.REFERRAL_BR_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ReferralAction() );
+        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 
+        // 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()][LdapConstants.SERVER_SASL_CREDENTIAL_TAG] = new GrammarTransition(
-            LdapStatesEnum.REFERRAL_BR_STATE, LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE,
-            LdapConstants.SERVER_SASL_CREDENTIAL_TAG, new ServerSASLCredsAction() );
+        super.transitions[LdapStatesEnum.REFERRAL_BR_STATE.ordinal()][LdapConstants.SERVER_SASL_CREDENTIAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_BR_STATE,
+                LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE,
+                LdapConstants.SERVER_SASL_CREDENTIAL_TAG,
+                new StoreServerSASLCreds() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Referral BR to Controls 
+        // Transition from Referral BR to Controls
         // --------------------------------------------------------------------------------------------
         //         bindResponse   BindResponse,
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
         // Adda new Referral
-        super.transitions[LdapStatesEnum.REFERRAL_BR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.REFERRAL_BR_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.REFERRAL_BR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_BR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Error Message BR to controls 
+        // Transition from Error Message BR to controls
         // --------------------------------------------------------------------------------------------
         //         bindResponse   BindResponse,
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        //  
-        super.transitions[LdapStatesEnum.ERROR_MESSAGE_BR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ERROR_MESSAGE_BR_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        //
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_BR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_BR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Server SASL credentials to Controls 
+        // Transition from Server SASL credentials to Controls
         // --------------------------------------------------------------------------------------------
         //         bindResponse   BindResponse,
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        super.transitions[LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SERVER_SASL_CREDENTIALS_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Result Code to Matched Dn
@@ -976,9 +660,12 @@
         //     ...
         //
         // Stores the matched Dn
-        super.transitions[LdapStatesEnum.RESULT_CODE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.RESULT_CODE_STATE, LdapStatesEnum.MATCHED_DN_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new MatchedDNAction() );
+        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
@@ -989,9 +676,12 @@
         //     ...
         //
         // Stores the error message
-        super.transitions[LdapStatesEnum.MATCHED_DN_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MATCHED_DN_STATE, LdapStatesEnum.ERROR_MESSAGE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ErrorMessageAction() );
+        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
@@ -1000,80 +690,71 @@
         //     ...
         //     referral   [3] Referral OPTIONNAL }
         //
-        // Initialize the referrals list 
-        super.transitions[LdapStatesEnum.ERROR_MESSAGE_STATE.ordinal()][LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG] = new GrammarTransition(
-            LdapStatesEnum.ERROR_MESSAGE_STATE, LdapStatesEnum.REFERRALS_STATE,
-            LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG, new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Init referrals list" )
-            {
-                public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
-                {
-                    TLV tlv = container.getCurrentTLV();
-
-                    // If we have a Referrals sequence, then it should not be empty
-                    // sasl credentials
-                    if ( tlv.getLength() == 0 )
-                    {
-                        String msg = I18n.err( I18n.ERR_04080 );
-                        LOG.error( msg );
-
-                        // This will generate a PROTOCOL_ERROR
-                        throw new DecoderException( msg );
-                    }
-
-                    Message response = container.getMessage();
-                    LdapResult ldapResult = ( ( ResultResponse ) response ).getLdapResult();
-
-                    Referral referral = new ReferralImpl();
-
-                    ldapResult.setReferral( referral );
-                }
-            } );
+        // Initialize the referrals list
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_STATE.ordinal()][LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_STATE,
+                LdapStatesEnum.REFERRALS_STATE,
+                LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG,
+                new InitReferrals() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Referrals to Referral 
+        // 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()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.REFERRALS_STATE, LdapStatesEnum.REFERRAL_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ReferralAction() );
+        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 
+        // 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()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.REFERRAL_STATE, LdapStatesEnum.REFERRAL_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ReferralAction() );
+        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 
+        // Transition from Referral to Controls
         // --------------------------------------------------------------------------------------------
         //         xxxResponse   xxxResponse,
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
         // Adda new Referral
-        super.transitions[LdapStatesEnum.REFERRAL_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.REFERRAL_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.REFERRAL_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Error Message to controls 
+        // Transition from Error Message to controls
         // --------------------------------------------------------------------------------------------
         //         xxxResponse   xxxResponse,
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        //  
-        super.transitions[LdapStatesEnum.ERROR_MESSAGE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ERROR_MESSAGE_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        //
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from MessageId to SearchResultEntry Message.
@@ -1082,18 +763,12 @@
         // SearchResultEntry ::= [APPLICATION 4] SEQUENCE { ...
         //
         // Initialize the searchResultEntry object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.SEARCH_RESULT_ENTRY_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.SEARCH_RESULT_ENTRY_STATE,
-            LdapConstants.SEARCH_RESULT_ENTRY_TAG, new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Init SearchResultEntry" )
-            {
-                public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container )
-                {
-                    // Now, we can allocate the SearchResultEntry Object
-                    SearchResultEntryDecorator searchResultEntry = new SearchResultEntryDecorator( 
-                        container.getLdapCodecService(), new SearchResultEntryImpl( container.getMessageId() ) );
-                    container.setMessage( searchResultEntry );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.SEARCH_RESULT_ENTRY_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.SEARCH_RESULT_ENTRY_STATE,
+                LdapConstants.SEARCH_RESULT_ENTRY_TAG,
+                new InitSearchResultEntry() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from SearchResultEntry Message to ObjectName
@@ -1103,50 +778,12 @@
         // ...
         //
         // Store the object name.
-        super.transitions[LdapStatesEnum.SEARCH_RESULT_ENTRY_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.SEARCH_RESULT_ENTRY_STATE, LdapStatesEnum.OBJECT_NAME_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<SearchResultEntryDecorator>>( "Store search result entry object name Value" )
-            {
-                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() );
-                    }
-                }
-            } );
+        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
@@ -1159,15 +796,12 @@
         // ...
         //
         // We may have no attributes. Just allows the grammar to end
-        super.transitions[LdapStatesEnum.OBJECT_NAME_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.OBJECT_NAME_STATE, LdapStatesEnum.ATTRIBUTES_SR_STATE, UniversalTag.SEQUENCE.getValue(),
-            new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Pop and end allowed" )
-            {
-                public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
-                {
-                    container.setGrammarEndAllowed( true );
-                }
-            } );
+        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
@@ -1180,9 +814,12 @@
         // ...
         //
         // nothing to do
-        super.transitions[LdapStatesEnum.ATTRIBUTES_SR_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTES_SR_STATE, LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE,
-            UniversalTag.SEQUENCE.getValue(), null );
+        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
@@ -1192,9 +829,12 @@
         // controls   [0] Controls OPTIONAL }
         //
         // Initialize the controls
-        super.transitions[LdapStatesEnum.ATTRIBUTES_SR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTES_SR_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.ATTRIBUTES_SR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTES_SR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from PartialAttributesList to typeSR
@@ -1208,49 +848,12 @@
         //     ...
         //
         // Store the attribute's name.
-        super.transitions[LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE, LdapStatesEnum.TYPE_SR_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<SearchResultEntryDecorator>>( "Store search result entry object name Value" )
-            {
-                public void action( LdapMessageContainer<SearchResultEntryDecorator> container ) throws DecoderException
-                {
-                    SearchResultEntryDecorator searchResultEntry = container.getMessage();
-
-                    TLV tlv = container.getCurrentTLV();
-
-                    String type = "";
-
-                    // Store the name
-                    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
-                    {
-                        type = getType(tlv.getValue().getData());
-
-                        try
-                        {
-                            searchResultEntry.addAttribute( type );
-                        }
-                        catch ( LdapException ine )
-                        {
-                            // 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 )
-                    {
-                        LOG.debug( "Attribute type : {}", type );
-                    }
-                }
-            } );
+        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
@@ -1264,15 +867,12 @@
         //     vals SET OF AttributeValue }
         //
         // We may have no value. Just allows the grammar to end
-        super.transitions[LdapStatesEnum.TYPE_SR_STATE.ordinal()][UniversalTag.SET.getValue()] = new GrammarTransition(
-            LdapStatesEnum.TYPE_SR_STATE, LdapStatesEnum.VALS_SR_STATE, UniversalTag.SET.getValue(), 
-            new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Grammar end allowed" )
-            {
-                public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
-                {
-                    container.setGrammarEndAllowed( true );
-                }
-            } );
+        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
@@ -1282,11 +882,14 @@
         //     vals SET OF AttributeValue }
         //
         // AttributeValue ::= OCTET STRING
-        // 
+        //
         // Store the attribute value
-        super.transitions[LdapStatesEnum.VALS_SR_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.VALS_SR_STATE, LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new SearchResultAttributeValueAction() );
+        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
@@ -1294,10 +897,13 @@
         // 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()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.VALS_SR_STATE, LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE, UniversalTag.SEQUENCE.getValue(), null );
+        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
@@ -1307,23 +913,29 @@
         // controls   [0] Controls OPTIONAL }
         //
         // Initialize the controls
-        super.transitions[LdapStatesEnum.VALS_SR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.VALS_SR_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.VALS_SR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.VALS_SR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from AttributeValueSR to AttributeValueSR 
+        // 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()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE, LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new SearchResultAttributeValueAction() );
+        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
@@ -1331,11 +943,13 @@
         // 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()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE, LdapStatesEnum.PARTIAL_ATTRIBUTES_LIST_STATE,
-            UniversalTag.SEQUENCE.getValue(), null );
+        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
@@ -1345,30 +959,25 @@
         // controls   [0] Controls OPTIONAL }
         //
         // Initialize the controls
-        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_VALUE_SR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // SearchResultDone Message.
         // --------------------------------------------------------------------------------------------
         // LdapMessage ::= ... SearchResultDone ...
         // SearchResultDone ::= [APPLICATION 5] SEQUENCE { ...
-        // 
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.SEARCH_RESULT_DONE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.SEARCH_RESULT_DONE_STATE,
-            LdapConstants.SEARCH_RESULT_DONE_TAG, new GrammarAction<LdapMessageContainer<SearchResultDoneDecorator>>( "Init search Result Done" )
-            {
-                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" );
-                }
-            } );
+        //
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.SEARCH_RESULT_DONE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.SEARCH_RESULT_DONE_STATE,
+                LdapConstants.SEARCH_RESULT_DONE_TAG,
+                new InitSearchResultDone() );
 
         // --------------------------------------------------------------------------------------------
         // SearchResultDone Message.
@@ -1379,11 +988,14 @@
         // LDAPResult ::= SEQUENCE {
         //     resultCode    ENUMERATED {
         //         ...
-        // 
+        //
         // Stores the result code
-        super.transitions[LdapStatesEnum.SEARCH_RESULT_DONE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.SEARCH_RESULT_DONE_STATE, LdapStatesEnum.RESULT_CODE_STATE, UniversalTag.ENUMERATED.getValue(),
-            new ResultCodeAction() );
+        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
@@ -1392,19 +1004,12 @@
         // ModifyRequest ::= [APPLICATION 6] SEQUENCE { ...
         //
         // Creates the Modify Request object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.MODIFY_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.MODIFY_REQUEST_STATE, LdapConstants.MODIFY_REQUEST_TAG,
-            new GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>( "Init ModifyRequest" )
-            {
-                public void action( LdapMessageContainer<ModifyRequestDecorator> container )
-                {
-                    // Now, we can allocate the ModifyRequest Object
-                    ModifyRequest modifyRequest = new ModifyRequestImpl( container.getMessageId() );
-                    ModifyRequestDecorator modifyRequestDecorator = new ModifyRequestDecorator( 
-                        container.getLdapCodecService(), modifyRequest );
-                    container.setMessage( modifyRequestDecorator );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.MODIFY_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.MODIFY_REQUEST_STATE,
+                LdapConstants.MODIFY_REQUEST_TAG,
+                new InitModifyRequest() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from ModifyRequest Message to Object
@@ -1414,53 +1019,12 @@
         //     ...
         //
         // Stores the object Dn
-        super.transitions[LdapStatesEnum.MODIFY_REQUEST_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MODIFY_REQUEST_STATE, LdapStatesEnum.OBJECT_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>( "Store Modify request object Value" )
-            {
-                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 )
-                    {
-                        ((ModifyRequest)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() );
-                    }
-                }
-            } );
+        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
@@ -1471,8 +1035,11 @@
         //     ...
         //
         // Initialize the modifications list
-        super.transitions[LdapStatesEnum.OBJECT_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.OBJECT_STATE, LdapStatesEnum.MODIFICATIONS_STATE, UniversalTag.SEQUENCE.getValue(), null );
+        super.transitions[LdapStatesEnum.OBJECT_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.OBJECT_STATE,
+                LdapStatesEnum.MODIFICATIONS_STATE,
+                SEQUENCE );
 
         // --------------------------------------------------------------------------------------------
         // Transition from modifications to modification sequence
@@ -1483,8 +1050,11 @@
         //     ...
         //
         // Nothing to do
-        super.transitions[LdapStatesEnum.MODIFICATIONS_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MODIFICATIONS_STATE, LdapStatesEnum.MODIFICATIONS_SEQ_STATE, UniversalTag.SEQUENCE.getValue(), null );
+        super.transitions[LdapStatesEnum.MODIFICATIONS_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MODIFICATIONS_STATE,
+                LdapStatesEnum.MODIFICATIONS_SEQ_STATE,
+                SEQUENCE );
 
         // --------------------------------------------------------------------------------------------
         // Transition from modification sequence to operation
@@ -1496,55 +1066,12 @@
         //             ...
         //
         // Store operation type
-        super.transitions[LdapStatesEnum.MODIFICATIONS_SEQ_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MODIFICATIONS_SEQ_STATE, LdapStatesEnum.OPERATION_STATE, UniversalTag.ENUMERATED.getValue(),
-            new GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>( "Store operation type" )
-            {
-                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 );
-                    }
-
-                    // Store the current operation.
-                    modifyRequestDecorator.setCurrentOperation( operation );
-
-                    if ( IS_DEBUG )
-                    {
-                        switch ( operation )
-                        {
-                            case LdapConstants.OPERATION_ADD:
-                                LOG.debug( "Modification operation : ADD" );
-                                break;
-
-                            case LdapConstants.OPERATION_DELETE:
-                                LOG.debug( "Modification operation : DELETE" );
-                                break;
-
-                            case LdapConstants.OPERATION_REPLACE:
-                                LOG.debug( "Modification operation : REPLACE" );
-                                break;
-                        }
-                    }
-
-                }
-            } );
+        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
@@ -1559,8 +1086,11 @@
         //     ...
         //
         // Nothing to do
-        super.transitions[LdapStatesEnum.OPERATION_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.OPERATION_STATE, LdapStatesEnum.MODIFICATION_STATE, UniversalTag.SEQUENCE.getValue(), null );
+        super.transitions[LdapStatesEnum.OPERATION_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.OPERATION_STATE,
+                LdapStatesEnum.MODIFICATION_STATE,
+                SEQUENCE );
 
         // --------------------------------------------------------------------------------------------
         // Transition from modification to TypeMod
@@ -1576,41 +1106,12 @@
         //     ...
         //
         // Stores the type
-        super.transitions[LdapStatesEnum.MODIFICATION_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MODIFICATION_STATE, LdapStatesEnum.TYPE_MOD_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>( "Store type" )
-            {
-                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 = getType(tlv.getValue().getData());
-                        modifyRequestDecorator.addAttributeTypeAndValues( type );
-                    }
-
-                    if ( IS_DEBUG )
-                    {
-                        LOG.debug( "Modifying type : {}", 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
@@ -1626,26 +1127,12 @@
         //     vals SET OF AttributeValue }
         //
         // Initialize the list of values
-        super.transitions[LdapStatesEnum.TYPE_MOD_STATE.ordinal()][UniversalTag.SET.getValue()] = new GrammarTransition(
-            LdapStatesEnum.TYPE_MOD_STATE, LdapStatesEnum.VALS_STATE, UniversalTag.SET.getValue(), 
-            new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Init Attribute vals" )
-            {
-                public void action( LdapMessageContainer<MessageDecorator<? extends Message>> 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" );
-                }
-            } );
+        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
@@ -1663,9 +1150,12 @@
         // AttributeValue ::= OCTET STRING
         //
         // Stores a value
-        super.transitions[LdapStatesEnum.VALS_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.VALS_STATE, LdapStatesEnum.ATTRIBUTE_VALUE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ModifyAttributeValueAction() );
+        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
@@ -1683,8 +1173,11 @@
         // AttributeValue ::= OCTET STRING
         //
         // Nothing to do
-        super.transitions[LdapStatesEnum.VALS_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.VALS_STATE, LdapStatesEnum.MODIFICATIONS_SEQ_STATE, UniversalTag.SEQUENCE.getValue(), null );
+        super.transitions[LdapStatesEnum.VALS_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VALS_STATE,
+                LdapStatesEnum.MODIFICATIONS_SEQ_STATE,
+                SEQUENCE );
 
         // --------------------------------------------------------------------------------------------
         // Transition from vals to Controls
@@ -1694,9 +1187,12 @@
         // controls   [0] Controls OPTIONAL }
         //
         // Nothing to do
-        super.transitions[LdapStatesEnum.VALS_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.VALS_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.VALS_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.VALS_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Attribute Value to Attribute Value
@@ -1714,9 +1210,12 @@
         // AttributeValue ::= OCTET STRING
         //
         // Stores a value
-        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_VALUE_STATE, LdapStatesEnum.ATTRIBUTE_VALUE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ModifyAttributeValueAction() );
+        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
@@ -1734,9 +1233,11 @@
         // AttributeValue ::= OCTET STRING
         //
         // Nothing to do
-        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_VALUE_STATE, LdapStatesEnum.MODIFICATIONS_SEQ_STATE, UniversalTag.SEQUENCE.getValue(),
-            null );
+        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
@@ -1746,9 +1247,12 @@
         // controls   [0] Controls OPTIONAL }
         //
         // Nothing to do
-        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_VALUE_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.ATTRIBUTE_VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // ModifyResponse Message.
@@ -1756,20 +1260,12 @@
         // LdapMessage ::= ... ModifyResponse ...
         // ModifyResponse ::= [APPLICATION 7] SEQUENCE { ...
         // We have to switch to the ModifyResponse grammar
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.MODIFY_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.MODIFY_RESPONSE_STATE, LdapConstants.MODIFY_RESPONSE_TAG,
-            new GrammarAction<LdapMessageContainer<ModifyResponseDecorator>>( "Init ModifyResponse" )
-            {
-                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" );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.MODIFY_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.MODIFY_RESPONSE_STATE,
+                LdapConstants.MODIFY_RESPONSE_TAG,
+                new InitModifyResponse() );
 
         // --------------------------------------------------------------------------------------------
         // ModifyResponse Message.
@@ -1780,11 +1276,14 @@
         // LDAPResult ::= SEQUENCE {
         //     resultCode    ENUMERATED {
         //         ...
-        // 
+        //
         // Stores the result code
-        super.transitions[LdapStatesEnum.MODIFY_RESPONSE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MODIFY_RESPONSE_STATE, LdapStatesEnum.RESULT_CODE_STATE, UniversalTag.ENUMERATED.getValue(),
-            new ResultCodeAction() );
+        super.transitions[LdapStatesEnum.MODIFY_RESPONSE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.MODIFY_RESPONSE_STATE,
+                LdapStatesEnum.RESULT_CODE_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
 
         // --------------------------------------------------------------------------------------------
         // AddRequest Message.
@@ -1793,31 +1292,12 @@
         // AddRequest ::= [APPLICATION 8] SEQUENCE { ...
         //
         // Initialize the AddRequest object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.ADD_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.ADD_REQUEST_STATE, LdapConstants.ADD_REQUEST_TAG,
-            new GrammarAction<LdapMessageContainer<AddRequestDecorator>>( "Init addRequest" )
-            {
-                public void action( LdapMessageContainer<AddRequestDecorator> container ) throws DecoderException
-                {
-                    // Now, we can allocate the AddRequest Object
-                    int messageId = container.getMessageId();
-                    AddRequestDecorator addRequest = new AddRequestDecorator( 
-                        container.getLdapCodecService(), new AddRequestImpl( messageId ) );
-                    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 );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.ADD_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.ADD_REQUEST_STATE,
+                LdapConstants.ADD_REQUEST_TAG,
+                new InitAddRequest() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Add Request to Entry
@@ -1827,56 +1307,12 @@
         //     ...
         //
         // Stores the Dn
-        super.transitions[LdapStatesEnum.ADD_REQUEST_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ADD_REQUEST_STATE, LdapStatesEnum.ENTRY_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<AddRequestDecorator>>( "Store add request object Value" )
-            {
-                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() );
-                }
-            } );
+        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
@@ -1885,11 +1321,14 @@
         //     ...
         //    attributes AttributeList }
         //
-        // AttributeList ::= SEQUENCE OF ... 
+        // AttributeList ::= SEQUENCE OF ...
         //
         // Initialize the attribute list
-        super.transitions[LdapStatesEnum.ENTRY_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ENTRY_STATE, LdapStatesEnum.ATTRIBUTES_STATE, UniversalTag.SEQUENCE.getValue(), null );
+        super.transitions[LdapStatesEnum.ENTRY_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ENTRY_STATE,
+                LdapStatesEnum.ATTRIBUTES_STATE,
+                SEQUENCE );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Attributes to Attribute
@@ -1897,8 +1336,11 @@
         // 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()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTES_STATE, LdapStatesEnum.ATTRIBUTE_STATE, UniversalTag.SEQUENCE.getValue(), null );
+        super.transitions[LdapStatesEnum.ATTRIBUTES_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTES_STATE,
+                LdapStatesEnum.ATTRIBUTE_STATE,
+                SEQUENCE );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Attribute to type
@@ -1910,50 +1352,12 @@
         // AttributeDescription LDAPString
         //
         // We store the type in the current attribute
-        super.transitions[LdapStatesEnum.ATTRIBUTE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_STATE, LdapStatesEnum.TYPE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<AddRequestDecorator>>( "Store attribute type" )
-            {
-                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 = getType(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 );
-                    }
-                }
-            } );
+        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
@@ -1963,8 +1367,11 @@
         //     vals SET OF AttributeValue }
         //
         // Nothing to do here.
-        super.transitions[LdapStatesEnum.TYPE_STATE.ordinal()][UniversalTag.SET.getValue()] = new GrammarTransition(
-            LdapStatesEnum.TYPE_STATE, LdapStatesEnum.VALUES_STATE, UniversalTag.SET.getValue(), null );
+        super.transitions[LdapStatesEnum.TYPE_STATE.ordinal()][SET.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPE_STATE,
+                LdapStatesEnum.VALUES_STATE,
+                SET );
 
         // --------------------------------------------------------------------------------------------
         // Transition from vals to Value
@@ -1976,8 +1383,12 @@
         // AttributeValue OCTET STRING
         //
         // Store the value into the current attribute
-        super.transitions[LdapStatesEnum.VALUES_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.VALUES_STATE, LdapStatesEnum.VALUE_STATE, UniversalTag.OCTET_STRING.getValue(), new ValueAction() );
+        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
@@ -1989,8 +1400,12 @@
         // AttributeValue OCTET STRING
         //
         // Store the value into the current attribute
-        super.transitions[LdapStatesEnum.VALUE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.VALUE_STATE, LdapStatesEnum.VALUE_STATE, UniversalTag.OCTET_STRING.getValue(), new ValueAction() );
+        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
@@ -1998,8 +1413,11 @@
         // AttributeList ::= SEQUENCE OF SEQUENCE {
         //
         // Nothing to do here.
-        super.transitions[LdapStatesEnum.VALUE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.VALUE_STATE, LdapStatesEnum.ATTRIBUTE_STATE, UniversalTag.SEQUENCE.getValue(), null );
+        super.transitions[LdapStatesEnum.VALUE_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.VALUE_STATE,
+                LdapStatesEnum.ATTRIBUTE_STATE,
+                SEQUENCE );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Value to Controls
@@ -2007,42 +1425,25 @@
         // AttributeList ::= SEQUENCE OF SEQUENCE {
         //
         // Initialize the controls
-        super.transitions[LdapStatesEnum.VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.VALUE_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // AddResponse Message.
         // --------------------------------------------------------------------------------------------
         // LdapMessage ::= ... AddResponse ...
         // AddResponse ::= [APPLICATION 9] LDAPResult
-        // 
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.ADD_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.ADD_RESPONSE_STATE, LdapConstants.ADD_RESPONSE_TAG,
-            new GrammarAction<LdapMessageContainer<AddResponseDecorator>>( "Init AddResponse" )
-            {
-                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" );
-                }
-            } );
+        //
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.ADD_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.ADD_RESPONSE_STATE,
+                LdapConstants.ADD_RESPONSE_TAG,
+                new InitAddResponse() );
 
         // --------------------------------------------------------------------------------------------
         // AddResponse Message.
@@ -2053,11 +1454,14 @@
         // LDAPResult ::= SEQUENCE {
         //     resultCode    ENUMERATED {
         //         ...
-        // 
+        //
         // Stores the result code
-        super.transitions[LdapStatesEnum.ADD_RESPONSE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ADD_RESPONSE_STATE, LdapStatesEnum.RESULT_CODE_STATE, UniversalTag.ENUMERATED.getValue(),
-            new ResultCodeAction() );
+        super.transitions[LdapStatesEnum.ADD_RESPONSE_STATE.ordinal()][ENUMERATED.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ADD_RESPONSE_STATE,
+                LdapStatesEnum.RESULT_CODE_STATE,
+                ENUMERATED,
+                new StoreResultCode() );
 
         // --------------------------------------------------------------------------------------------
         // DelResponse Message.
@@ -2065,20 +1469,12 @@
         // LdapMessage ::= ... DelResponse ...
         // DelResponse ::= [APPLICATION 11] LDAPResult
         // We have to switch to the DelResponse grammar
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.DEL_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.DEL_RESPONSE_STATE, LdapConstants.DEL_RESPONSE_TAG,
-            new GrammarAction<LdapMessageContainer<DeleteResponseDecorator>>( "Init DelResponse" )
-            {
-                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 " );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.DEL_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.DEL_RESPONSE_STATE,
+                LdapConstants.DEL_RESPONSE_TAG,
+                new InitDelResponse() );
 
         // --------------------------------------------------------------------------------------------
         // DelResponse Message.
@@ -2089,11 +1485,14 @@
         // LDAPResult ::= SEQUENCE {
         //     resultCode    ENUMERATED {
         //         ...
-        // 
+        //
         // Stores the result code
-        super.transitions[LdapStatesEnum.DEL_RESPONSE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.DEL_RESPONSE_STATE, LdapStatesEnum.RESULT_CODE_STATE, UniversalTag.ENUMERATED.getValue(),
-            new ResultCodeAction() );
+        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.
@@ -2102,20 +1501,12 @@
         // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { ...
         //
         // Create the ModifyDNRequest Object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.MODIFY_DN_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.MODIFY_DN_REQUEST_STATE,
-            LdapConstants.MODIFY_DN_REQUEST_TAG, new GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>( "Init Modify Dn Request" )
-            {
-                public void action( LdapMessageContainer<ModifyDnRequestDecorator> container )
-                {
-                    // Now, we can allocate the ModifyDNRequest Object
-                    ModifyDnRequestDecorator modifyDnRequest = new ModifyDnRequestDecorator( 
-                        container.getLdapCodecService(), new ModifyDnRequestImpl( container.getMessageId() ) );
-                    container.setMessage( modifyDnRequest );
-
-                    LOG.debug( "ModifyDn request" );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.MODIFY_DN_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.MODIFY_DN_REQUEST_STATE,
+                LdapConstants.MODIFY_DN_REQUEST_TAG,
+                new InitModifyDnRequest() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from ModifydDNRequest Message to EntryModDN
@@ -2125,55 +1516,12 @@
         //     ...
         //
         // Stores the entry Dn
-        super.transitions[LdapStatesEnum.MODIFY_DN_REQUEST_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MODIFY_DN_REQUEST_STATE, LdapStatesEnum.ENTRY_MOD_DN_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>( "Store entry" )
-            {
-                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 );
-                    }
-                }
-            } );
+        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
@@ -2186,60 +1534,12 @@
         // RelativeRDN :: LDAPString
         //
         // Stores the new Rdn
-        super.transitions[LdapStatesEnum.ENTRY_MOD_DN_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ENTRY_MOD_DN_STATE, LdapStatesEnum.NEW_RDN_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>( "Store new Rdn" )
-            {
-                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( 0 );
-                        }
-                        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 );
-                    }
-                }
-            } );
+        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
@@ -2250,53 +1550,12 @@
         //     ...
         //
         // Stores the deleteOldRDN flag
-        super.transitions[LdapStatesEnum.NEW_RDN_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] = new GrammarTransition(
-            LdapStatesEnum.NEW_RDN_STATE, LdapStatesEnum.DELETE_OLD_RDN_STATE, UniversalTag.BOOLEAN.getValue(),
-            new GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>( "Store matching dnAttributes Value" )
-            {
-                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.
-                    Value 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() );
-                    }
-
-                    // 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" );
-                        }
-                    }
-                }
-            } );
+        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
@@ -2306,69 +1565,12 @@
         //     newSuperior [0] LDAPDN OPTIONAL }
         //
         // Stores the new superior
-        super.transitions[LdapStatesEnum.DELETE_OLD_RDN_STATE.ordinal()][LdapConstants.MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG] = new GrammarTransition(
-            LdapStatesEnum.DELETE_OLD_RDN_STATE, LdapStatesEnum.NEW_SUPERIOR_STATE,
-            LdapConstants.MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG, 
-            new GrammarAction<LdapMessageContainer<ModifyDnRequestDecorator>>( "Store new superior" )
-            {
-                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 );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.DELETE_OLD_RDN_STATE.ordinal()][LdapConstants.MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DELETE_OLD_RDN_STATE,
+                LdapStatesEnum.NEW_SUPERIOR_STATE,
+                LdapConstants.MODIFY_DN_REQUEST_NEW_SUPERIOR_TAG,
+                new StoreModifyDnRequestNewSuperior() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from DeleteOldRDN to Controls
@@ -2378,9 +1580,12 @@
         // controls   [0] Controls OPTIONAL }
         //
         // Stores the new superior
-        super.transitions[LdapStatesEnum.DELETE_OLD_RDN_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.DELETE_OLD_RDN_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.DELETE_OLD_RDN_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DELETE_OLD_RDN_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from DeleteOldRDN to Controls
@@ -2390,9 +1595,12 @@
         // controls   [0] Controls OPTIONAL }
         //
         // Stores the new superior
-        super.transitions[LdapStatesEnum.NEW_SUPERIOR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.NEW_SUPERIOR_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.NEW_SUPERIOR_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NEW_SUPERIOR_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from MessageID to ModifyDNResponse Message.
@@ -2401,20 +1609,12 @@
         //     ...
         //
         // Creates the ModifyDNResponse
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.MODIFY_DN_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.MODIFY_DN_RESPONSE_STATE,
-            LdapConstants.MODIFY_DN_RESPONSE_TAG, new GrammarAction<LdapMessageContainer<ModifyDnResponseDecorator>>( "Init ModifyDNResponse" )
-            {
-                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 " );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.MODIFY_DN_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.MODIFY_DN_RESPONSE_STATE,
+                LdapConstants.MODIFY_DN_RESPONSE_TAG,
+                new InitModifyDnResponse() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from ModifyDNResponse Message to Result Code
@@ -2425,37 +1625,32 @@
         // LDAPResult ::= SEQUENCE {
         //     resultCode    ENUMERATED {
         //         ...
-        // 
+        //
         // Stores the result co        //     modifyDNRequest ModifyDNRequest,
         //     ... },
         // controls   [0] Controls OPTIONAL }
-        super.transitions[LdapStatesEnum.MODIFY_DN_RESPONSE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MODIFY_DN_RESPONSE_STATE, LdapStatesEnum.RESULT_CODE_STATE, UniversalTag.ENUMERATED.getValue(),
-            new ResultCodeAction() );
+        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()][LdapConstants.COMPARE_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.COMPARE_REQUEST_STATE, LdapConstants.COMPARE_REQUEST_TAG,
-            new GrammarAction<LdapMessageContainer<CompareRequestDecorator>>( "Init Compare Request" )
-            {
-                public void action( LdapMessageContainer<CompareRequestDecorator> container )
-                {
-                    // Now, we can allocate the CompareRequest Object
-                    CompareRequestDecorator compareRequest = new CompareRequestDecorator( 
-                        container.getLdapCodecService(), new CompareRequestImpl( container.getMessageId() ) );
-                    container.setMessage( compareRequest );
-
-                    LOG.debug( "Compare Request" );
-                }
-            } );
+        // Initialize the Compare Request object
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.COMPARE_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.COMPARE_REQUEST_STATE,
+                LdapConstants.COMPARE_REQUEST_TAG,
+                new InitCompareRequest() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from CompareResquest to entryComp
@@ -2465,54 +1660,12 @@
         //     ...
         //
         // Stores the compared Dn
-        super.transitions[LdapStatesEnum.COMPARE_REQUEST_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.COMPARE_REQUEST_STATE, LdapStatesEnum.ENTRY_COMP_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<CompareRequestDecorator>>( "Store entry" )
-            {
-                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 );
-                    }
-                }
-            } );
+        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
@@ -2522,10 +1675,13 @@
         //     ava AttributeValueAssertion }
         //
         // AttributeValueAssertion ::= SEQUENCE {
-        // 
+        //
         // Nothing to do
-        super.transitions[LdapStatesEnum.ENTRY_COMP_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ENTRY_COMP_STATE, LdapStatesEnum.AVA_STATE, UniversalTag.SEQUENCE.getValue(), null );
+        super.transitions[LdapStatesEnum.ENTRY_COMP_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.ENTRY_COMP_STATE,
+                LdapStatesEnum.AVA_STATE,
+                SEQUENCE );
 
         // --------------------------------------------------------------------------------------------
         // Transition from ava to AttributeDesc
@@ -2535,41 +1691,14 @@
         //     ...
         //
         // AttributeDescription LDAPString
-        // 
+        //
         // Stores the attribute description
-        super.transitions[LdapStatesEnum.AVA_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.AVA_STATE, LdapStatesEnum.ATTRIBUTE_DESC_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<CompareRequestDecorator>>( "Store attribute desc" )
-            {
-                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 = getType(tlv.getValue().getData());
-                    compareRequest.setAttributeId( type );
-
-                    if ( IS_DEBUG )
-                    {
-                        LOG.debug( "Comparing attribute description {}", compareRequest.getAttributeId() );
-                    }
-                }
-            } );
+        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
@@ -2579,52 +1708,14 @@
         //     assertionValue AssertionValue }
         //
         // AssertionValue OCTET STRING
-        // 
+        //
         // Stores the attribute value
-        super.transitions[LdapStatesEnum.ATTRIBUTE_DESC_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_DESC_STATE, LdapStatesEnum.ASSERTION_VALUE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<CompareRequestDecorator>>( "Store assertion value" )
-            {
-                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 );
-                }
-            } );
+        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
@@ -2634,11 +1725,14 @@
         //     assertionValue AssertionValue }
         //
         // AssertionValue OCTET STRING
-        // 
+        //
         // Stores the attribute value
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // CompareResponse Message.
@@ -2646,30 +1740,12 @@
         // LdapMessage ::= ... CompareResponse ...
         // CompareResponse ::= [APPLICATION 15] LDAPResult
         // We have to switch to the CompareResponse grammar
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.COMPARE_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.COMPARE_RESPONSE_STATE, LdapConstants.COMPARE_RESPONSE_TAG,
-            new GrammarAction<LdapMessageContainer<CompareResponseDecorator>>( "Init CompareResponse" )
-            {
-                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 " );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.COMPARE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.COMPARE_RESPONSE_STATE,
+                LdapConstants.COMPARE_RESPONSE_TAG,
+                new InitCompareResponse() );
 
         // --------------------------------------------------------------------------------------------
         // CompareResponse Message.
@@ -2680,11 +1756,14 @@
         // LDAPResult ::= SEQUENCE {
         //     resultCode    ENUMERATED {
         //         ...
-        // 
+        //
         // Stores the result code
-        super.transitions[LdapStatesEnum.COMPARE_RESPONSE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.COMPARE_RESPONSE_STATE, LdapStatesEnum.RESULT_CODE_STATE, UniversalTag.ENUMERATED.getValue(),
-            new ResultCodeAction() );
+        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.
@@ -2693,20 +1772,12 @@
         // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
         //
         // Initialization of SearchResultReference object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.SEARCH_RESULT_REFERENCE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.SEARCH_RESULT_REFERENCE_STATE,
-            LdapConstants.SEARCH_RESULT_REFERENCE_TAG, new GrammarAction<LdapMessageContainer<SearchResultReferenceDecorator>>( "Init SearchResultReference" )
-            {
-                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 " );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.SEARCH_RESULT_REFERENCE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.SEARCH_RESULT_REFERENCE_STATE,
+                LdapConstants.SEARCH_RESULT_REFERENCE_TAG,
+                new InitSearchResultReference() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from SearchResultReference Message to Reference
@@ -2715,9 +1786,12 @@
         // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
         //
         // Initialization of SearchResultReference object
-        super.transitions[LdapStatesEnum.SEARCH_RESULT_REFERENCE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.SEARCH_RESULT_REFERENCE_STATE, LdapStatesEnum.REFERENCE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new StoreReferenceAction() );
+        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
@@ -2726,9 +1800,12 @@
         // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
         //
         // Initialization of SearchResultReference object
-        super.transitions[LdapStatesEnum.REFERENCE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.REFERENCE_STATE, LdapStatesEnum.REFERENCE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new StoreReferenceAction() );
+        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
@@ -2738,9 +1815,12 @@
         // controls   [0] Controls OPTIONAL }
         //
         // Initialization the controls
-        super.transitions[LdapStatesEnum.REFERENCE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.REFERENCE_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.REFERENCE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERENCE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Message Id to ExtendedRequest Message
@@ -2749,20 +1829,12 @@
         // ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
         //
         // Creates the ExtendedRequest object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.EXTENDED_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.EXTENDED_REQUEST_STATE, LdapConstants.EXTENDED_REQUEST_TAG,
-            new GrammarAction<LdapMessageContainer<ExtendedRequestDecorator>>( "Init Extended Request" )
-            {
-                public void action( LdapMessageContainer<ExtendedRequestDecorator> container ) throws DecoderException
-                {
-                    // Now, we can allocate the ExtendedRequest Object
-                    ExtendedRequestDecorator extendedRequest = new ExtendedRequestDecorator( 
-                        container.getLdapCodecService(), new ExtendedRequestImpl( container.getMessageId() ) );
-                    container.setMessage( extendedRequest );
-
-                    LOG.debug( "Extended request" );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.EXTENDED_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.EXTENDED_REQUEST_STATE,
+                LdapConstants.EXTENDED_REQUEST_TAG,
+                new InitExtendedRequest() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from ExtendedRequest Message to RequestName
@@ -2772,70 +1844,12 @@
         //     ...
         //
         // Stores the name
-        super.transitions[LdapStatesEnum.EXTENDED_REQUEST_STATE.ordinal()][LdapConstants.EXTENDED_REQUEST_NAME_TAG] = new GrammarTransition(
-            LdapStatesEnum.EXTENDED_REQUEST_STATE, LdapStatesEnum.REQUEST_NAME_STATE,
-            LdapConstants.EXTENDED_REQUEST_NAME_TAG, new GrammarAction<LdapMessageContainer<ExtendedRequestDecorator>>( "Store name" )
-            {
-                public void action( LdapMessageContainer<ExtendedRequestDecorator> container ) throws DecoderException
-                {
-                    // We can allocate the ExtendedRequest Object
-                    ExtendedRequest 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
-                    // 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 );
-                            }
-
-                            extendedRequest.setRequestName( requestName );
-                        }
-                        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 : {}", extendedRequest.getRequestName() );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.EXTENDED_REQUEST_STATE.ordinal()][LdapConstants.EXTENDED_REQUEST_NAME_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.EXTENDED_REQUEST_STATE,
+                LdapStatesEnum.REQUEST_NAME_STATE,
+                LdapConstants.EXTENDED_REQUEST_NAME_TAG,
+                new StoreExtendedRequestName() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from RequestName to RequestValue
@@ -2845,38 +1859,12 @@
         //     requestValue  [1] OCTET STRING OPTIONAL }
         //
         // Stores the value
-        super.transitions[LdapStatesEnum.REQUEST_NAME_STATE.ordinal()][LdapConstants.EXTENDED_REQUEST_VALUE_TAG] = new GrammarTransition(
-            LdapStatesEnum.REQUEST_NAME_STATE, LdapStatesEnum.REQUEST_VALUE_STATE,
-            LdapConstants.EXTENDED_REQUEST_VALUE_TAG, new GrammarAction<LdapMessageContainer<ExtendedRequestDecorator>>( "Store value" )
-            {
-                public void action( LdapMessageContainer<ExtendedRequestDecorator> container ) throws DecoderException
-                {
-                    // We can allocate the ExtendedRequest Object
-                    ExtendedRequest 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() );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.REQUEST_NAME_STATE.ordinal()][LdapConstants.EXTENDED_REQUEST_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REQUEST_NAME_STATE,
+                LdapStatesEnum.REQUEST_VALUE_STATE,
+                LdapConstants.EXTENDED_REQUEST_VALUE_TAG,
+                new StoreExtendedRequestValue() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from RequestName to Controls
@@ -2886,9 +1874,12 @@
         //     controls       [0] Controls OPTIONAL }
         //
         // Stores the value
-        super.transitions[LdapStatesEnum.REQUEST_NAME_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.REQUEST_NAME_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.REQUEST_NAME_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REQUEST_NAME_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from RequestValue to Controls
@@ -2898,9 +1889,12 @@
         //     controls       [0] Controls OPTIONAL }
         //
         // Stores the value
-        super.transitions[LdapStatesEnum.REQUEST_VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.REQUEST_VALUE_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.REQUEST_VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REQUEST_VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from MessageId to ExtendedResponse Message.
@@ -2909,20 +1903,12 @@
         // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
         //
         // Creates the ExtendeResponse object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.EXTENDED_RESPONSE_STATE,
-            LdapConstants.EXTENDED_RESPONSE_TAG, new GrammarAction<LdapMessageContainer<ExtendedResponseDecorator>>( "Init Extended Reponse" )
-            {
-                public void action( LdapMessageContainer<ExtendedResponseDecorator> container ) throws DecoderException
-                {
-                    // Now, we can allocate the ExtendedResponse Object
-                    ExtendedResponseDecorator extendedResponse = new ExtendedResponseDecorator( 
-                        container.getLdapCodecService(), new ExtendedResponseImpl( container.getMessageId() ) );
-                    container.setMessage( extendedResponse );
-
-                    LOG.debug( "Extended Response" );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.EXTENDED_RESPONSE_STATE,
+                LdapConstants.EXTENDED_RESPONSE_TAG,
+                new InitExtendedResponse() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from ExtendedResponse Message to Result Code ER
@@ -2933,9 +1919,12 @@
         //     ...
         //
         // Stores the result code
-        super.transitions[LdapStatesEnum.EXTENDED_RESPONSE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.EXTENDED_RESPONSE_STATE, LdapStatesEnum.RESULT_CODE_ER_STATE, UniversalTag.ENUMERATED.getValue(),
-            new ResultCodeAction() );
+        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
@@ -2945,10 +1934,13 @@
         //     COMPONENTS OF LDAPResult,
         //     ...
         //
-        // 
-        super.transitions[LdapStatesEnum.RESULT_CODE_ER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.RESULT_CODE_ER_STATE, LdapStatesEnum.MATCHED_DN_ER_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new MatchedDNAction() );
+        //
+        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
@@ -2958,95 +1950,119 @@
         //     COMPONENTS OF LDAPResult,
         //     ...
         //
-        // 
-        super.transitions[LdapStatesEnum.MATCHED_DN_ER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MATCHED_DN_ER_STATE, LdapStatesEnum.ERROR_MESSAGE_ER_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ErrorMessageAction() );
+        //
+        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 
+        // 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()][LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG] = new GrammarTransition(
-            LdapStatesEnum.ERROR_MESSAGE_ER_STATE, LdapStatesEnum.REFERRALS_ER_STATE,
-            LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG, new InitReferralsAction() );
+        //
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_ER_STATE,
+                LdapStatesEnum.REFERRALS_ER_STATE,
+                LdapConstants.LDAP_RESULT_REFERRAL_SEQUENCE_TAG,
+                new InitReferrals() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Referrals ER to Referral ER 
+        // 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()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.REFERRALS_ER_STATE, LdapStatesEnum.REFERRAL_ER_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ReferralAction() );
+        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 
+        // 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()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.REFERRAL_ER_STATE, LdapStatesEnum.REFERRAL_ER_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ReferralAction() );
+        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 
+        // 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()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG] = new GrammarTransition(
-            LdapStatesEnum.REFERRAL_ER_STATE, LdapStatesEnum.RESPONSE_NAME_STATE,
-            LdapConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG, new ResponseNameAction() );
+        super.transitions[LdapStatesEnum.REFERRAL_ER_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_ER_STATE,
+                LdapStatesEnum.RESPONSE_NAME_STATE,
+                LdapConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG,
+                new StoreResponseName() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Referral ER to Response 
+        // Transition from Referral ER to Response
         // --------------------------------------------------------------------------------------------
         // Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI (RFC 4511)
         // URI ::= LDAPString
         //
-        // Adda new Referral
-        super.transitions[LdapStatesEnum.REFERRAL_ER_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.REFERRAL_ER_STATE, LdapStatesEnum.RESPONSE_STATE,
-            LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG, new ResponseAction() );
+        // Add a new Referral
+        super.transitions[LdapStatesEnum.REFERRAL_ER_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_ER_STATE,
+                LdapStatesEnum.RESPONSE_STATE,
+                LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG,
+                new StoreExtendedResponseValue() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Referral ER to Controls 
+        // Transition from Referral ER to Controls
         // --------------------------------------------------------------------------------------------
         //         extendedResponse   ExtendedResponse,
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
         // Adda new Referral
-        super.transitions[LdapStatesEnum.REFERRAL_ER_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.REFERRAL_ER_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.REFERRAL_ER_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.REFERRAL_ER_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Error Message ER to Controls 
+        // Transition from Error Message ER to Controls
         // --------------------------------------------------------------------------------------------
         // LdapMessage ::= ... ExtendedResponse ...
         // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
         //     COMPONENTS OF LDAPResult,
         //     ...
         //
-        // 
-        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ERROR_MESSAGE_ER_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        //
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_ER_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Error Message ER to ResponseName 
+        // Transition from Error Message ER to ResponseName
         // --------------------------------------------------------------------------------------------
         // LdapMessage ::= ... ExtendedResponse ...
         // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
@@ -3055,12 +2071,15 @@
         //     ...
         //
         // Stores the response name
-        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG] = new GrammarTransition(
-            LdapStatesEnum.ERROR_MESSAGE_ER_STATE, LdapStatesEnum.RESPONSE_NAME_STATE,
-            LdapConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG, new ResponseNameAction() );
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_ER_STATE,
+                LdapStatesEnum.RESPONSE_NAME_STATE,
+                LdapConstants.EXTENDED_RESPONSE_RESPONSE_NAME_TAG,
+                new StoreResponseName() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Response Name to Response 
+        // Transition from Response Name to Response
         // --------------------------------------------------------------------------------------------
         // LdapMessage ::= ... ExtendedResponse ...
         // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
@@ -3069,24 +2088,30 @@
         //     response       [11] OCTET STRING OPTIONAL}
         //
         // Stores the response
-        super.transitions[LdapStatesEnum.RESPONSE_NAME_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.RESPONSE_NAME_STATE, LdapStatesEnum.RESPONSE_STATE,
-            LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG, new ResponseAction() );
+        super.transitions[LdapStatesEnum.RESPONSE_NAME_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.RESPONSE_NAME_STATE,
+                LdapStatesEnum.RESPONSE_STATE,
+                LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG,
+                new StoreExtendedResponseValue() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from ResponseName to Controls 
+        // Transition from ResponseName to Controls
         // --------------------------------------------------------------------------------------------
         //         extendedRequest   EtendedRequest,
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
         // Init the controls
-        super.transitions[LdapStatesEnum.RESPONSE_NAME_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.RESPONSE_NAME_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.RESPONSE_NAME_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.RESPONSE_NAME_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Error Message ER to Response 
+        // Transition from Error Message ER to Response
         // --------------------------------------------------------------------------------------------
         // LdapMessage ::= ... ExtendedResponse ...
         // ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
@@ -3095,21 +2120,27 @@
         //     response       [11] OCTET STRING OPTIONAL}
         //
         // Stores the response
-        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.ERROR_MESSAGE_ER_STATE, LdapStatesEnum.RESPONSE_STATE,
-            LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG, new ResponseAction() );
+        super.transitions[LdapStatesEnum.ERROR_MESSAGE_ER_STATE.ordinal()][LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ERROR_MESSAGE_ER_STATE,
+                LdapStatesEnum.RESPONSE_STATE,
+                LdapConstants.EXTENDED_RESPONSE_RESPONSE_TAG,
+                new StoreExtendedResponseValue() );
 
         // --------------------------------------------------------------------------------------------
-        // Transition from Response to Controls 
+        // Transition from Response to Controls
         // --------------------------------------------------------------------------------------------
         //         extendedRequest   EtendedRequest,
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
         // Init the controls
-        super.transitions[LdapStatesEnum.RESPONSE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.RESPONSE_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.RESPONSE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.RESPONSE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Message Id to IntermediateResponse Message
@@ -3118,21 +2149,12 @@
         // IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
         //
         // Creates the IntermediateResponse object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.INTERMEDIATE_RESPONSE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE,
-            LdapConstants.INTERMEDIATE_RESPONSE_TAG, new GrammarAction<LdapMessageContainer<IntermediateResponseDecorator>>( "Init Intermediate Response" )
-            {
-                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" );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.INTERMEDIATE_RESPONSE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE,
+                LdapConstants.INTERMEDIATE_RESPONSE_TAG,
+                new InitIntermediateResponse() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from IntermediateResponse Message to ResponseName
@@ -3142,59 +2164,12 @@
         //     ...
         //
         // Stores the name
-        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE.ordinal()][LdapConstants.INTERMEDIATE_RESPONSE_NAME_TAG] = new GrammarTransition(
-            LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE, LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE,
-            LdapConstants.INTERMEDIATE_RESPONSE_NAME_TAG, new GrammarAction<LdapMessageContainer<IntermediateResponseDecorator>>( "Store response name" )
-            {
-                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() );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE.ordinal()][LdapConstants.INTERMEDIATE_RESPONSE_NAME_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE,
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE,
+                LdapConstants.INTERMEDIATE_RESPONSE_NAME_TAG,
+                new StoreIntermediateResponseName() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from IntermediateResponse Message to ResponseValue (ResponseName is null)
@@ -3205,39 +2180,12 @@
         //     }
         //
         // Stores the value
-        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE.ordinal()][LdapConstants.INTERMEDIATE_RESPONSE_VALUE_TAG] = new GrammarTransition(
-            LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE, LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE,
-            LdapConstants.INTERMEDIATE_RESPONSE_VALUE_TAG, 
-            new GrammarAction<LdapMessageContainer<IntermediateResponseDecorator>>( "Store response value" )
-            {
-                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()) );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE.ordinal()][LdapConstants.INTERMEDIATE_RESPONSE_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_STATE,
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE,
+                LdapConstants.INTERMEDIATE_RESPONSE_VALUE_TAG,
+                new StoreIntermediateResponseValue() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from ResponseName to ResponseValue
@@ -3247,39 +2195,12 @@
         //     responseValue  [1] OCTET STRING OPTIONAL }
         //
         // Stores the value
-        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE.ordinal()][LdapConstants.INTERMEDIATE_RESPONSE_VALUE_TAG] = new GrammarTransition(
-            LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE, LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE,
-            LdapConstants.INTERMEDIATE_RESPONSE_VALUE_TAG, 
-            new GrammarAction<LdapMessageContainer<IntermediateResponseDecorator>>( "Store value" )
-            {
-                public void action( LdapMessageContainer<IntermediateResponseDecorator> container ) throws DecoderException
-                {
-                    // We can allocate the ExtendedRequest 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( "Response value : {}", intermediateResponse.getResponseValue() );
-                    }
-                }
-            } );
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE.ordinal()][LdapConstants.INTERMEDIATE_RESPONSE_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE,
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE,
+                LdapConstants.INTERMEDIATE_RESPONSE_VALUE_TAG,
+                new StoreIntermediateResponseValue() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from ResponseName to Controls
@@ -3289,9 +2210,12 @@
         //     controls       [0] Controls OPTIONAL }
         //
         // Stores the value
-        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_NAME_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from ResponseValue to Controls
@@ -3301,32 +2225,12 @@
         //     controls       [0] Controls OPTIONAL }
         //
         // Stores the value
-        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE, LdapStatesEnum.CONTROLS_STATE,
-            LdapConstants.CONTROLS_TAG, new ControlsInitAction() );
-
-        // --------------------------------------------------------------------------------------------
-        // Controls
-        // --------------------------------------------------------------------------------------------
-        Action<LdapMessageContainer<MessageDecorator<? extends Message>>> addControl = 
-            new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Add Control" )
-        {
-            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 );
-                }
-            }
-        };
+        super.transitions[LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INTERMEDIATE_RESPONSE_VALUE_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // ============================================================================================
         // Transition from Controls to Control
@@ -3335,9 +2239,13 @@
         // Controls ::= SEQUENCE OF Control
         //  ...
         //
-        // Initialize the controls 
-        super.transitions[LdapStatesEnum.CONTROLS_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.CONTROLS_STATE, LdapStatesEnum.CONTROL_STATE, UniversalTag.SEQUENCE.getValue(), addControl );
+        // 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
@@ -3346,52 +2254,12 @@
         //     ...
         //
         // Create a new Control object, and store it in the message Container
-        super.transitions[LdapStatesEnum.CONTROL_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.CONTROL_STATE, LdapStatesEnum.CONTROL_TYPE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Set Control Type" )
-            {
-                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 );
-                    }
-                }
-            } );
+        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
@@ -3402,51 +2270,12 @@
         //     ...
         //
         // Store the value in the control object created before
-        super.transitions[LdapStatesEnum.CONTROL_TYPE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] = new GrammarTransition(
-            LdapStatesEnum.CONTROL_TYPE_STATE, LdapStatesEnum.CRITICALITY_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Set Criticality" )
-            {
-                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.
-                    Value 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() );
-                    }
-
-                    // We can have an END transition
-                    container.setGrammarEndAllowed( true );
-
-                    if ( IS_DEBUG )
-                    {
-                        LOG.debug( "Control criticality : " + control.isCritical() );
-                    }
-                }
-            } );
+        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
@@ -3456,9 +2285,12 @@
         //     controlValue OCTET STRING OPTIONAL }
         //
         // Store the value in the control object created before
-        super.transitions[LdapStatesEnum.CRITICALITY_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.CRITICALITY_STATE, LdapStatesEnum.CONTROL_VALUE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ControlValueAction() );
+        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
@@ -3468,9 +2300,12 @@
         //     controlValue OCTET STRING OPTIONAL }
         //
         // Store the value in the control object created before
-        super.transitions[LdapStatesEnum.CONTROL_TYPE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.CONTROL_TYPE_STATE, LdapStatesEnum.CONTROL_VALUE_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new ControlValueAction() );
+        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
@@ -3480,8 +2315,12 @@
         //     controlValue OCTET STRING OPTIONAL }
         //
         // Store the value in the control object created before
-        super.transitions[LdapStatesEnum.CONTROL_TYPE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.CONTROL_TYPE_STATE, LdapStatesEnum.CONTROL_STATE, UniversalTag.SEQUENCE.getValue(), addControl );
+        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
@@ -3491,8 +2330,12 @@
         //     controlValue OCTET STRING OPTIONAL }
         //
         // Store the value in the control object created before
-        super.transitions[LdapStatesEnum.CRITICALITY_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.CRITICALITY_STATE, LdapStatesEnum.CONTROL_STATE, UniversalTag.SEQUENCE.getValue(), addControl );
+        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
@@ -3502,8 +2345,12 @@
         //     controlValue OCTET STRING OPTIONAL }
         //
         // Store the value in the control object created before
-        super.transitions[LdapStatesEnum.CONTROL_VALUE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.CONTROL_VALUE_STATE, LdapStatesEnum.CONTROL_STATE, UniversalTag.SEQUENCE.getValue(), addControl );
+        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
@@ -3512,24 +2359,12 @@
         // SearchRequest ::= [APPLICATION 3] SEQUENCE { ...
         //
         // Initialize the searchRequest object
-        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.SEARCH_REQUEST_TAG] = new GrammarTransition(
-            LdapStatesEnum.MESSAGE_ID_STATE, LdapStatesEnum.SEARCH_REQUEST_STATE, LdapConstants.SEARCH_REQUEST_TAG,
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "Init SearchRequest" )
-            {
-                public void action( LdapMessageContainer<SearchRequestDecorator> container )
-                {
-                    // Now, we can allocate the SearchRequest Object
-                    TLV tlv = container.getCurrentTLV();
-
-                    SearchRequestDecorator searchRequest = new SearchRequestDecorator( 
-                        container.getLdapCodecService(), new SearchRequestImpl( container.getMessageId() ) );
-
-                    searchRequest.setTlvId( tlv.getId());
-                    container.setMessage( searchRequest );
-
-                    LOG.debug( "Search Request" );
-                }
-            } );
+        super.transitions[LdapStatesEnum.MESSAGE_ID_STATE.ordinal()][LdapConstants.SEARCH_REQUEST_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MESSAGE_ID_STATE,
+                LdapStatesEnum.SEARCH_REQUEST_STATE,
+                LdapConstants.SEARCH_REQUEST_TAG,
+                new InitSearchRequest() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from SearchRequest Message to BaseObject
@@ -3539,54 +2374,12 @@
         //     ...
         //
         // We have a value for the base object, we will store it in the message
-        super.transitions[LdapStatesEnum.SEARCH_REQUEST_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.SEARCH_REQUEST_STATE, LdapStatesEnum.BASE_OBJECT_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "store base object value" )
-            {
-                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 );
-                }
-            } );
+        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
@@ -3600,53 +2393,12 @@
         //     ...
         //
         // We have a value for the scope, we will store it in the message
-        super.transitions[LdapStatesEnum.BASE_OBJECT_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.BASE_OBJECT_STATE, LdapStatesEnum.SCOPE_STATE, UniversalTag.ENUMERATED.getValue(),
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "store scope value" )
-            {
-                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
-                    Value value = tlv.getValue();
-                    int scope = 0;
-
-                    try
-                    {
-                        scope = IntegerDecoder.parse( value, LdapConstants.SCOPE_BASE_OBJECT,
-                            LdapConstants.SCOPE_WHOLE_SUBTREE );
-                    }
-                    catch ( IntegerDecoderException ide )
-                    {
-                        String msg = I18n.err( I18n.ERR_04101, value.toString() );
-                        LOG.error( msg );
-                        throw new DecoderException( msg );
-                    }
-
-                    searchRequest.setScope( SearchScope.getSearchScope(scope) );
-
-                    if ( IS_DEBUG )
-                    {
-                        switch ( scope )
-                        {
-                            case LdapConstants.SCOPE_BASE_OBJECT:
-                                LOG.debug( "Searching within BASE_OBJECT scope " );
-                                break;
-
-                            case LdapConstants.SCOPE_SINGLE_LEVEL:
-                                LOG.debug( "Searching within SINGLE_LEVEL scope " );
-                                break;
-
-                            case LdapConstants.SCOPE_WHOLE_SUBTREE:
-                                LOG.debug( "Searching within WHOLE_SUBTREE scope " );
-                                break;
-                        }
-                    }
-                }
-            } );
+        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
@@ -3661,57 +2413,12 @@
         //     ...
         //
         // We have a value for the derefAliases, we will store it in the message
-        super.transitions[LdapStatesEnum.SCOPE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = new GrammarTransition(
-            LdapStatesEnum.SCOPE_STATE, LdapStatesEnum.DEREF_ALIAS_STATE, UniversalTag.ENUMERATED.getValue(),
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "store derefAliases value" )
-            {
-                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
-                    Value value = tlv.getValue();
-                    int derefAliases = 0;
-
-                    try
-                    {
-                        derefAliases = IntegerDecoder.parse(value, LdapConstants.NEVER_DEREF_ALIASES,
-                                LdapConstants.DEREF_ALWAYS);
-                    }
-                    catch ( IntegerDecoderException ide )
-                    {
-                        String msg = I18n.err( I18n.ERR_04102, value.toString() );
-                        LOG.error( msg );
-                        throw new DecoderException( msg );
-                    }
-
-                    searchRequest.setDerefAliases( AliasDerefMode.getDerefMode( derefAliases ) );
-
-                    if ( IS_DEBUG )
-                    {
-                        switch ( derefAliases )
-                        {
-                            case LdapConstants.NEVER_DEREF_ALIASES:
-                                LOG.debug( "Handling object strategy : NEVER_DEREF_ALIASES" );
-                                break;
-
-                            case LdapConstants.DEREF_IN_SEARCHING:
-                                LOG.debug( "Handling object strategy : DEREF_IN_SEARCHING" );
-                                break;
-
-                            case LdapConstants.DEREF_FINDING_BASE_OBJ:
-                                LOG.debug( "Handling object strategy : DEREF_FINDING_BASE_OBJ" );
-                                break;
-
-                            case LdapConstants.DEREF_ALWAYS:
-                                LOG.debug( "Handling object strategy : DEREF_ALWAYS" );
-                                break;
-                        }
-                    }
-                }
-            } );
+        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
@@ -3722,40 +2429,12 @@
         //     ...
         //
         // We have a value for the sizeLimit, we will store it in the message
-        super.transitions[LdapStatesEnum.DEREF_ALIAS_STATE.ordinal()][UniversalTag.INTEGER.getValue()] = new GrammarTransition(
-            LdapStatesEnum.DEREF_ALIAS_STATE, LdapStatesEnum.SIZE_LIMIT_STATE, UniversalTag.INTEGER.getValue(),
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "store sizeLimit value" )
-            {
-                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
-                    Value 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 );
-                    }
-
-                    searchRequest.setSizeLimit( sizeLimit );
-
-                    if ( IS_DEBUG )
-                    {
-                        LOG.debug( "The sizeLimit value is set to {} objects", Long.valueOf( sizeLimit ) );
-                    }
-                }
-            } );
+        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
@@ -3766,41 +2445,12 @@
         //     ...
         //
         // We have a value for the timeLimit, we will store it in the message
-        super.transitions[LdapStatesEnum.SIZE_LIMIT_STATE.ordinal()][UniversalTag.INTEGER.getValue()] = new GrammarTransition(
-            LdapStatesEnum.SIZE_LIMIT_STATE, LdapStatesEnum.TIME_LIMIT_STATE, UniversalTag.INTEGER.getValue(),
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "store timeLimit value" )
-            {
-                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
-                    Value 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 );
-                    }
-
-                    searchRequest.setTimeLimit( timeLimit );
-
-                    if ( IS_DEBUG )
-                    {
-                        LOG.debug( "The timeLimit value is set to {} seconds", Integer.valueOf( timeLimit ) );
-                    }
-                }
-            } );
+        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
@@ -3811,48 +2461,17 @@
         //     ...
         //
         // We have a value for the typesOnly, we will store it in the message.
-        super.transitions[LdapStatesEnum.TIME_LIMIT_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] = new GrammarTransition(
-            LdapStatesEnum.TIME_LIMIT_STATE, LdapStatesEnum.TYPES_ONLY_STATE, UniversalTag.BOOLEAN.getValue(),
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "store typesOnly value" )
-            {
-                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.
-                    Value 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() );
-                    }
-
-                    if ( IS_DEBUG )
-                    {
-                        LOG.debug( "The search will return {}", ( searchRequest.getTypesOnly() ? "only attributs type"
-                            : "attributes types and values" ) );
-                    }
-                }
-            } );
+        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 
+        // 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 :
@@ -3874,14 +2493,14 @@
         //|   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       | 
+        //|         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      | 
+        //|         04 08 'contacts'    | 82 36 14       | 38 36 14      |
         //|                             |    ^  ^             ^  ^       |
         //|                             |    |  |             |  |       |
         //|                             |    |  +-------------|--+       |
@@ -3889,7 +2508,7 @@
         //+-----------------------------* 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 0B 'objectclass' | 82 20 18       | 38 0 13       |
         //|         04 03 'ttt'         | 82 20 18       | 60 20 18      |
         //|                             |    ^  ^             ^  ^       |
         //|                             |    |  |             |  |       |
@@ -3899,7 +2518,7 @@
         //|   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         | 
+        //|         82 03 'top'         | 82 20          | 82 20         |
         //|                             | ^  ^             ^  ^          |
         //|                             | |  |             |  |          |
         //|                             | |  +-------------|--+          |
@@ -3926,9 +2545,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG,
-            new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from TypesOnly to OR filter
@@ -3944,9 +2566,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG,
-            new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from TypesOnly to NOT filter
@@ -3962,9 +2587,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG,
-            new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from TypesOnly to Equality Match filter
@@ -3980,9 +2608,12 @@
         //     ...
         //
         // Init Equality filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE,
-            LdapConstants.EQUALITY_MATCH_FILTER_TAG, new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from TypesOnly to Substrings filter
@@ -3998,9 +2629,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE,
-            LdapConstants.SUBSTRINGS_FILTER_TAG, new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from TypesOnly to GreaterOrEqual filter
@@ -4016,9 +2650,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE,
-            LdapConstants.GREATER_OR_EQUAL_FILTER_TAG, new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from TypesOnly to LessOrEqual filter
@@ -4034,9 +2671,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE,
-            LdapConstants.LESS_OR_EQUAL_FILTER_TAG, new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from TypesOnly to Present filter
@@ -4052,9 +2692,12 @@
         //     ...
         //
         // Init Present Match filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from TypesOnly to Approx Match filter
@@ -4070,9 +2713,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.APPROX_MATCH_STATE, LdapConstants.APPROX_MATCH_FILTER_TAG,
-            new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from TypesOnly to Extensible Match filter
@@ -4088,9 +2734,12 @@
         //     ...
         //
         // Init Extensible Match filter
-        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPES_ONLY_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
-            LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG, new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.TYPES_ONLY_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPES_ONLY_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to AND filter
@@ -4105,8 +2754,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG, new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to OR filter
@@ -4122,8 +2775,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG, new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to NOT filter
@@ -4139,8 +2796,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG, new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to Equality Match filter
@@ -4156,9 +2817,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE, LdapConstants.EQUALITY_MATCH_FILTER_TAG,
-            new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to Substrings filter
@@ -4174,9 +2838,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE, LdapConstants.SUBSTRINGS_FILTER_TAG,
-            new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to GreaterOrEqual filter
@@ -4192,9 +2859,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE, LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
-            new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to LessOrEqual filter
@@ -4210,9 +2880,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE, LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
-            new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to Present filter
@@ -4228,9 +2901,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to Approx Match filter
@@ -4246,9 +2922,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.APPROX_MATCH_STATE, LdapConstants.APPROX_MATCH_FILTER_TAG,
-            new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from AND to Extensible Match filter
@@ -4264,9 +2943,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.AND_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE, LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
-            new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.AND_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.AND_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to AND filter
@@ -4281,8 +2963,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG, new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to OR filter
@@ -4298,8 +2984,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG, new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to NOT filter
@@ -4315,8 +3005,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG, new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to Equality Match filter
@@ -4332,9 +3026,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE, LdapConstants.EQUALITY_MATCH_FILTER_TAG,
-            new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to Substrings filter
@@ -4350,9 +3047,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE, LdapConstants.SUBSTRINGS_FILTER_TAG,
-            new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to GreaterOrEqual filter
@@ -4368,9 +3068,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE, LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
-            new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to LessOrEqual filter
@@ -4386,9 +3089,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE, LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
-            new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to Present filter
@@ -4404,9 +3110,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to Approx Match filter
@@ -4422,9 +3131,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.APPROX_MATCH_STATE, LdapConstants.APPROX_MATCH_FILTER_TAG,
-            new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from OR to Extensible Match filter
@@ -4440,9 +3152,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.OR_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE, LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
-            new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.OR_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.OR_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to AND filter
@@ -4457,8 +3172,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG, new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to OR filter
@@ -4474,8 +3193,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG, new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to NOT filter
@@ -4491,8 +3214,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG, new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to Equality Match filter
@@ -4508,9 +3235,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE, LdapConstants.EQUALITY_MATCH_FILTER_TAG,
-            new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to Substrings filter
@@ -4526,9 +3256,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE, LdapConstants.SUBSTRINGS_FILTER_TAG,
-            new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to GreaterOrEqual filter
@@ -4544,9 +3277,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE, LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
-            new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to LessOrEqual filter
@@ -4562,9 +3298,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE, LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
-            new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to Present filter
@@ -4580,9 +3319,12 @@
         //     ...
         //
         // Init present filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to Approx Match filter
@@ -4598,9 +3340,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.APPROX_MATCH_STATE, LdapConstants.APPROX_MATCH_FILTER_TAG,
-            new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from NOT to Extensible Match filter
@@ -4616,9 +3361,12 @@
         //     ...
         //
         // Init extensible match filter
-        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.NOT_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE, LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
-            new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.NOT_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.NOT_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Equality match to Attribute Desc Filter
@@ -4633,9 +3381,12 @@
         //     ...
         //
         // Init Attribute Desc filter
-        super.transitions[LdapStatesEnum.EQUALITY_MATCH_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.EQUALITY_MATCH_STATE, LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new InitAttributeDescFilterAction() );
+        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
@@ -4650,9 +3401,12 @@
         //     assertionValue   AssertionValue }
         //
         // Init Assertion Value filter
-        super.transitions[LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE, LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new InitAssertionValueFilterAction() );
+        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
@@ -4667,9 +3421,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG,
-            new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to OR filter
@@ -4685,9 +3442,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG,
-            new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to NOT filter
@@ -4703,9 +3463,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG,
-            new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to Equality Match filter
@@ -4721,9 +3484,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE,
-            LdapConstants.EQUALITY_MATCH_FILTER_TAG, new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to Substrings filter
@@ -4739,9 +3505,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE,
-            LdapConstants.SUBSTRINGS_FILTER_TAG, new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to GreaterOrEqual filter
@@ -4757,9 +3526,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE,
-            LdapConstants.GREATER_OR_EQUAL_FILTER_TAG, new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to LessOrEqual filter
@@ -4775,9 +3547,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE,
-            LdapConstants.LESS_OR_EQUAL_FILTER_TAG, new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to Present filter
@@ -4793,9 +3568,12 @@
         //     ...
         //
         // Init present filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.PRESENT_STATE,
-            LdapConstants.PRESENT_FILTER_TAG, new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to Approx Match filter
@@ -4811,9 +3589,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.APPROX_MATCH_STATE,
-            LdapConstants.APPROX_MATCH_FILTER_TAG, new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to Extensible Match filter
@@ -4829,9 +3610,12 @@
         //     ...
         //
         // Init Assertion Value Filter filter
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
-            LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG, new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Assertion Value Filter to Attribute Description List
@@ -4845,9 +3629,12 @@
         //     AttributeDescription
         //
         // Init attribute description list
-        super.transitions[LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ASSERTION_VALUE_FILTER_STATE, LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
-            UniversalTag.SEQUENCE.getValue(), new InitAttributeDescListAction() );
+        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
@@ -4861,9 +3648,12 @@
         //     AttributeDescription
         //
         // Store attribute description
-        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE, LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new AttributeDescAction() );
+        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
@@ -4873,9 +3663,12 @@
         //     controls       [0] Controls OPTIONAL }
         //
         // Empty attribute description list, with controls
-        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Attribute Description to AttributeDescription
@@ -4889,9 +3682,12 @@
         //     AttributeDescription
         //
         // Store attribute description
-        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE, LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new AttributeDescAction() );
+        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.
@@ -4900,9 +3696,12 @@
         //         ... },
         //     controls       [0] Controls OPTIONAL }
         //
-        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE.ordinal()][LdapConstants.CONTROLS_TAG] = new GrammarTransition(
-            LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE, LdapStatesEnum.CONTROLS_STATE, LdapConstants.CONTROLS_TAG,
-            new ControlsInitAction() );
+        super.transitions[LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE.ordinal()][LdapConstants.CONTROLS_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_STATE,
+                LdapStatesEnum.CONTROLS_STATE,
+                LdapConstants.CONTROLS_TAG,
+                new InitControls() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Greater Or Equal to Attribute Desc Filter
@@ -4917,9 +3716,12 @@
         //     ...
         //
         // Init Attribute Desc filter
-        super.transitions[LdapStatesEnum.GREATER_OR_EQUAL_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.GREATER_OR_EQUAL_STATE, LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new InitAttributeDescFilterAction() );
+        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
@@ -4934,9 +3736,12 @@
         //     ...
         //
         // Init Attribute Desc filter
-        super.transitions[LdapStatesEnum.LESS_OR_EQUAL_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.LESS_OR_EQUAL_STATE, LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new InitAttributeDescFilterAction() );
+        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
@@ -4951,36 +3756,12 @@
         //     ...
         //
         // Init substring type
-        super.transitions[LdapStatesEnum.SUBSTRING_FILTER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.SUBSTRING_FILTER_STATE, LdapStatesEnum.TYPE_SUBSTRING_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "Store substring filter type" )
-            {
-                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 = getType(tlv.getValue().getData());
-                        substringFilter.setType( type );
-
-                        // We now have to get back to the nearest filter which
-                        // is not terminal.
-                        searchRequestDecorator.setTerminalFilter( substringFilter );
-                    }
-                }
-            } );
+        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
@@ -4996,21 +3777,12 @@
         //     ...
         //
         // Init substring type
-        super.transitions[LdapStatesEnum.TYPE_SUBSTRING_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.TYPE_SUBSTRING_STATE, LdapStatesEnum.SUBSTRINGS_STATE, UniversalTag.SEQUENCE.getValue(),
-            new GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>( "Substring Filter substringsSequence " )
-            {
-                public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
-                {
-                    TLV tlv = container.getCurrentTLV();
-
-                    if ( tlv.getLength() == 0 )
-                    {
-                        LOG.error( I18n.err( I18n.ERR_04107 ) );
-                        throw new DecoderException( "The substring sequence is empty" );
-                    }
-                }
-            } );
+        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
@@ -5022,33 +3794,12 @@
         //         ...
         //
         // Store initial value
-        super.transitions[LdapStatesEnum.SUBSTRINGS_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_INITIAL_TAG] = new GrammarTransition(
-            LdapStatesEnum.SUBSTRINGS_STATE, LdapStatesEnum.INITIAL_STATE, LdapConstants.SUBSTRINGS_FILTER_INITIAL_TAG,
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "Store substring filter initial Value" )
-            {
-                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 );
-                }
-            } );
+        super.transitions[LdapStatesEnum.SUBSTRINGS_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_INITIAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SUBSTRINGS_STATE,
+                LdapStatesEnum.INITIAL_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_INITIAL_TAG,
+                new StoreInitial() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from substrings to any
@@ -5061,9 +3812,12 @@
         //         ...
         //
         // Store substring any type
-        super.transitions[LdapStatesEnum.SUBSTRINGS_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_ANY_TAG] = new GrammarTransition(
-            LdapStatesEnum.SUBSTRINGS_STATE, LdapStatesEnum.ANY_STATE, LdapConstants.SUBSTRINGS_FILTER_ANY_TAG,
-            new StoreAnyAction() );
+        super.transitions[LdapStatesEnum.SUBSTRINGS_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_ANY_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SUBSTRINGS_STATE,
+                LdapStatesEnum.ANY_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_ANY_TAG,
+                new StoreAny() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from substrings to final
@@ -5075,9 +3829,12 @@
         //         final  [2] LDAPSTRING }
         //
         // Store substring final type
-        super.transitions[LdapStatesEnum.SUBSTRINGS_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG] = new GrammarTransition(
-            LdapStatesEnum.SUBSTRINGS_STATE, LdapStatesEnum.FINAL_STATE, LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG,
-            new StoreFinalAction() );
+        super.transitions[LdapStatesEnum.SUBSTRINGS_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.SUBSTRINGS_STATE,
+                LdapStatesEnum.FINAL_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG,
+                new StoreFinal() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to any
@@ -5090,9 +3847,12 @@
         //         ...
         //
         // Store substring any type
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_ANY_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.ANY_STATE, LdapConstants.SUBSTRINGS_FILTER_ANY_TAG,
-            new StoreAnyAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_ANY_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.ANY_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_ANY_TAG,
+                new StoreAny() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to final
@@ -5104,9 +3864,12 @@
         //         final  [2] LDAPSTRING }
         //
         // Store substring final type
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.FINAL_STATE, LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG,
-            new StoreFinalAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.FINAL_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG,
+                new StoreFinal() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to Attribute Description List
@@ -5120,9 +3883,12 @@
         //     AttributeDescription
         //
         // Init attribute description list
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE, UniversalTag.SEQUENCE.getValue(),
-            new InitAttributeDescListAction() );
+        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
@@ -5137,9 +3903,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG,
-            new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to OR filter
@@ -5155,9 +3924,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG,
-            new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to NOT filter
@@ -5173,9 +3945,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG,
-            new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to Equality Match filter
@@ -5191,9 +3966,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE, LdapConstants.EQUALITY_MATCH_FILTER_TAG,
-            new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to Substrings filter
@@ -5209,9 +3987,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE, LdapConstants.SUBSTRINGS_FILTER_TAG,
-            new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to GreaterOrEqual filter
@@ -5227,9 +4008,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE,
-            LdapConstants.GREATER_OR_EQUAL_FILTER_TAG, new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to LessOrEqual filter
@@ -5245,9 +4029,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE, LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
-            new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to Present filter
@@ -5263,9 +4050,12 @@
         //     ...
         //
         // Init present filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to Approx Match filter
@@ -5281,9 +4071,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.APPROX_MATCH_STATE, LdapConstants.APPROX_MATCH_FILTER_TAG,
-            new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from initial to Extensible Match filter
@@ -5299,9 +4092,12 @@
         //     ...
         //
         // Init Assertion Value Filter filter
-        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.INITIAL_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
-            LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG, new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.INITIAL_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.INITIAL_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to final
@@ -5313,9 +4109,12 @@
         //         final  [2] LDAPSTRING }
         //
         // Store substring final type
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.FINAL_STATE, LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG,
-            new StoreFinalAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.FINAL_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_FINAL_TAG,
+                new StoreFinal() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to any
@@ -5324,13 +4123,16 @@
         //     ...
         //     substrings SEQUENCE OF CHOICE {
         //         ...
-        //         any  [1] LDAPSTRING 
+        //         any  [1] LDAPSTRING
         //         ...
         //
         // Store substring any type
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_ANY_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.ANY_STATE, LdapConstants.SUBSTRINGS_FILTER_ANY_TAG,
-            new StoreAnyAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_ANY_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.ANY_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_ANY_TAG,
+                new StoreAny() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to Attribute Description List
@@ -5344,9 +4146,12 @@
         //     AttributeDescription
         //
         // Init attribute description list
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE, UniversalTag.SEQUENCE.getValue(),
-            new InitAttributeDescListAction() );
+        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
@@ -5361,8 +4166,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG, new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to OR filter
@@ -5378,8 +4187,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG, new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to NOT filter
@@ -5395,8 +4208,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG, new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to Equality Match filter
@@ -5412,9 +4229,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE, LdapConstants.EQUALITY_MATCH_FILTER_TAG,
-            new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to Substrings filter
@@ -5430,9 +4250,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE, LdapConstants.SUBSTRINGS_FILTER_TAG,
-            new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to GreaterOrEqual filter
@@ -5448,9 +4271,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE, LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
-            new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to LessOrEqual filter
@@ -5466,9 +4292,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE, LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
-            new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to Present filter
@@ -5484,9 +4313,12 @@
         //     ...
         //
         // Init present filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to Approx Match filter
@@ -5502,9 +4334,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.APPROX_MATCH_STATE, LdapConstants.APPROX_MATCH_FILTER_TAG,
-            new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from any to Extensible Match filter
@@ -5520,9 +4355,12 @@
         //     ...
         //
         // Init Assertion Value Filter filter
-        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.ANY_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE, LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
-            new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.ANY_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.ANY_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to Attribute Description List
@@ -5536,9 +4374,12 @@
         //     AttributeDescription
         //
         // Init attribute description list
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE, UniversalTag.SEQUENCE.getValue(),
-            new InitAttributeDescListAction() );
+        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
@@ -5553,9 +4394,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG,
-            new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to OR filter
@@ -5571,8 +4415,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG, new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to NOT filter
@@ -5588,9 +4436,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG,
-            new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to Equality Match filter
@@ -5606,9 +4457,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE, LdapConstants.EQUALITY_MATCH_FILTER_TAG,
-            new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to Substrings filter
@@ -5624,9 +4478,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE, LdapConstants.SUBSTRINGS_FILTER_TAG,
-            new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to GreaterOrEqual filter
@@ -5642,9 +4499,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE,
-            LdapConstants.GREATER_OR_EQUAL_FILTER_TAG, new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to LessOrEqual filter
@@ -5660,9 +4520,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE, LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
-            new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to Present filter
@@ -5678,9 +4541,12 @@
         //     ...
         //
         // Init present filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to Approx Match filter
@@ -5696,9 +4562,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.APPROX_MATCH_STATE, LdapConstants.APPROX_MATCH_FILTER_TAG,
-            new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from final to Extensible Match filter
@@ -5714,9 +4583,12 @@
         //     ...
         //
         // Init Assertion Value Filter filter
-        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.FINAL_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
-            LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG, new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.FINAL_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.FINAL_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to AND filter
@@ -5731,9 +4603,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG,
-            new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to OR filter
@@ -5749,9 +4624,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG,
-            new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to NOT filter
@@ -5767,9 +4645,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG,
-            new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to Equality Match filter
@@ -5785,9 +4666,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE, LdapConstants.EQUALITY_MATCH_FILTER_TAG,
-            new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to Substrings filter
@@ -5803,9 +4687,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE, LdapConstants.SUBSTRINGS_FILTER_TAG,
-            new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to GreaterOrEqual filter
@@ -5821,9 +4708,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE,
-            LdapConstants.GREATER_OR_EQUAL_FILTER_TAG, new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to LessOrEqual filter
@@ -5839,9 +4729,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE, LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
-            new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to Present filter
@@ -5857,9 +4750,12 @@
         //     ...
         //
         // Init present filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to Approx Match filter
@@ -5875,9 +4771,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.APPROX_MATCH_STATE, LdapConstants.APPROX_MATCH_FILTER_TAG,
-            new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to Extensible Match filter
@@ -5893,9 +4792,12 @@
         //     ...
         //
         // Init Assertion Value Filter filter
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
-            LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG, new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.PRESENT_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Present Filter to Attribute Description List
@@ -5909,9 +4811,12 @@
         //     AttributeDescription
         //
         // Init attribute description list
-        super.transitions[LdapStatesEnum.PRESENT_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.PRESENT_STATE, LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE, UniversalTag.SEQUENCE.getValue(),
-            new InitAttributeDescListAction() );
+        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
@@ -5926,9 +4831,12 @@
         //     ...
         //
         // Init Attribute Desc filter
-        super.transitions[LdapStatesEnum.APPROX_MATCH_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            LdapStatesEnum.APPROX_MATCH_STATE, LdapStatesEnum.ATTRIBUTE_DESC_FILTER_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new InitAttributeDescFilterAction() );
+        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
@@ -5941,7 +4849,7 @@
         //     matchingRule [1] MatchingRuleId OPTIONAL,
         //     ...
         //
-        // Store the matching rule ID 
+        // Store the matching rule ID
         super.transitions[LdapStatesEnum.EXTENSIBLE_MATCH_STATE.ordinal()][LdapConstants.MATCHING_RULE_ID_TAG] = new GrammarTransition(
             LdapStatesEnum.EXTENSIBLE_MATCH_STATE, LdapStatesEnum.MATCHING_RULE_STATE,
             LdapConstants.MATCHING_RULE_ID_TAG, new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "Store matching rule Value" )
@@ -5983,10 +4891,13 @@
         //     type [2] AttributeDescription OPTIONAL,
         //     ...
         //
-        // Store the matching rule ID 
-        super.transitions[LdapStatesEnum.EXTENSIBLE_MATCH_STATE.ordinal()][LdapConstants.MATCHING_RULE_TYPE_TAG] = new GrammarTransition(
-            LdapStatesEnum.EXTENSIBLE_MATCH_STATE, LdapStatesEnum.TYPE_MATCHING_RULE_STATE,
-            LdapConstants.MATCHING_RULE_TYPE_TAG, new StoreTypeMatchingRuleAction() );
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.EXTENSIBLE_MATCH_STATE.ordinal()][LdapConstants.MATCHING_RULE_TYPE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapStatesEnum.TYPE_MATCHING_RULE_STATE,
+                LdapConstants.MATCHING_RULE_TYPE_TAG,
+                new StoreTypeMatchingRule() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from Extensible Match to match value
@@ -6000,10 +4911,13 @@
         //     matchValue [3] AssertionValue,
         //     ...
         //
-        // Store the matching rule ID 
-        super.transitions[LdapStatesEnum.EXTENSIBLE_MATCH_STATE.ordinal()][LdapConstants.MATCH_VALUE_TAG] = new GrammarTransition(
-            LdapStatesEnum.EXTENSIBLE_MATCH_STATE, LdapStatesEnum.MATCH_VALUE_STATE, LdapConstants.MATCH_VALUE_TAG,
-            new StoreMatchValueAction() );
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.EXTENSIBLE_MATCH_STATE.ordinal()][LdapConstants.MATCH_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapConstants.MATCH_VALUE_TAG,
+                new StoreMatchValue() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from matching rule to type matching rule
@@ -6017,10 +4931,13 @@
         //     type [2] AttributeDescription OPTIONAL,
         //     ...
         //
-        // Store the matching rule ID 
-        super.transitions[LdapStatesEnum.MATCHING_RULE_STATE.ordinal()][LdapConstants.MATCHING_RULE_TYPE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCHING_RULE_STATE, LdapStatesEnum.TYPE_MATCHING_RULE_STATE,
-            LdapConstants.MATCHING_RULE_TYPE_TAG, new StoreTypeMatchingRuleAction() );
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.MATCHING_RULE_STATE.ordinal()][LdapConstants.MATCHING_RULE_TYPE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCHING_RULE_STATE,
+                LdapStatesEnum.TYPE_MATCHING_RULE_STATE,
+                LdapConstants.MATCHING_RULE_TYPE_TAG,
+                new StoreTypeMatchingRule() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from matching rule to match value
@@ -6034,10 +4951,13 @@
         //     matchValue [3] AssertionValue,
         //     ...
         //
-        // Store the matching rule ID 
-        super.transitions[LdapStatesEnum.MATCHING_RULE_STATE.ordinal()][LdapConstants.MATCH_VALUE_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCHING_RULE_STATE, LdapStatesEnum.MATCH_VALUE_STATE, LdapConstants.MATCH_VALUE_TAG,
-            new StoreMatchValueAction() );
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.MATCHING_RULE_STATE.ordinal()][LdapConstants.MATCH_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCHING_RULE_STATE,
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapConstants.MATCH_VALUE_TAG,
+                new StoreMatchValue() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from matching type to match value
@@ -6051,10 +4971,13 @@
         //     matchValue [3] AssertionValue,
         //     ...
         //
-        // Store the matching rule ID 
-        super.transitions[LdapStatesEnum.TYPE_MATCHING_RULE_STATE.ordinal()][LdapConstants.MATCH_VALUE_TAG] = new GrammarTransition(
-            LdapStatesEnum.TYPE_MATCHING_RULE_STATE, LdapStatesEnum.MATCH_VALUE_STATE, LdapConstants.MATCH_VALUE_TAG,
-            new StoreMatchValueAction() );
+        // Store the matching rule ID
+        super.transitions[LdapStatesEnum.TYPE_MATCHING_RULE_STATE.ordinal()][LdapConstants.MATCH_VALUE_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.TYPE_MATCHING_RULE_STATE,
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapConstants.MATCH_VALUE_TAG,
+                new StoreMatchValue() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to dnAttributes
@@ -6067,50 +4990,13 @@
         //     ...
         //     dnAttributes [4] BOOLEAN DEFAULT FALSE }
         //
-        // Store the dnAttributes flag 
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.DN_ATTRIBUTES_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.DN_ATTRIBUTES_STATE,
-            LdapConstants.DN_ATTRIBUTES_FILTER_TAG, 
-            new GrammarAction<LdapMessageContainer<SearchRequestDecorator>>( "Store matching dnAttributes 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();
-
-                    // 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.
-                    Value 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() );
-                    }
-
-                    if ( IS_DEBUG )
-                    {
-                        LOG.debug( "Dn Attributes : {}", Boolean.valueOf( extensibleMatchFilter.isDnAttributes() ) );
-                    }
-
-                    // unstack the filters if needed
-                    searchRequest.unstackFilters( container );
-                }
-            } );
+        // Store the dnAttributes flag
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.DN_ATTRIBUTES_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapConstants.DN_ATTRIBUTES_FILTER_TAG,
+                new StoreMatchingRuleDnAttributes() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to AND filter
@@ -6125,9 +5011,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG,
-            new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to OR filter
@@ -6143,9 +5032,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG,
-            new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to NOT filter
@@ -6161,9 +5053,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG,
-            new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to Equality Match filter
@@ -6179,9 +5074,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE,
-            LdapConstants.EQUALITY_MATCH_FILTER_TAG, new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to Substrings filter
@@ -6197,9 +5095,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE,
-            LdapConstants.SUBSTRINGS_FILTER_TAG, new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to GreaterOrEqual filter
@@ -6215,9 +5116,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE,
-            LdapConstants.GREATER_OR_EQUAL_FILTER_TAG, new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to LessOrEqual filter
@@ -6233,9 +5137,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE,
-            LdapConstants.LESS_OR_EQUAL_FILTER_TAG, new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to Present filter
@@ -6251,9 +5158,12 @@
         //     ...
         //
         // Init present filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to Approx Match filter
@@ -6269,9 +5179,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.APPROX_MATCH_STATE, LdapConstants.APPROX_MATCH_FILTER_TAG,
-            new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to Extensible Match filter
@@ -6287,9 +5200,12 @@
         //     ...
         //
         // Init Assertion Value Filter filter
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
-            LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG, new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.MATCH_VALUE_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from match value to Attribute Description List
@@ -6303,9 +5219,12 @@
         //     AttributeDescription
         //
         // Init attribute description list
-        super.transitions[LdapStatesEnum.MATCH_VALUE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.MATCH_VALUE_STATE, LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
-            UniversalTag.SEQUENCE.getValue(), new InitAttributeDescListAction() );
+        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
@@ -6320,9 +5239,12 @@
         //     ...
         //
         // Init AND filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.AND_STATE, LdapConstants.AND_FILTER_TAG,
-            new InitAndFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.AND_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.AND_STATE,
+                LdapConstants.AND_FILTER_TAG,
+                new InitAndFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to OR filter
@@ -6338,9 +5260,12 @@
         //     ...
         //
         // Init OR filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.OR_STATE, LdapConstants.OR_FILTER_TAG,
-            new InitOrFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.OR_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.OR_STATE,
+                LdapConstants.OR_FILTER_TAG,
+                new InitOrFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to NOT filter
@@ -6356,9 +5281,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.NOT_STATE, LdapConstants.NOT_FILTER_TAG,
-            new InitNotFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.NOT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.NOT_STATE,
+                LdapConstants.NOT_FILTER_TAG,
+                new InitNotFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to Equality Match filter
@@ -6374,9 +5302,12 @@
         //     ...
         //
         // Init NOT filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.EQUALITY_MATCH_STATE,
-            LdapConstants.EQUALITY_MATCH_FILTER_TAG, new InitEqualityMatchFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.EQUALITY_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.EQUALITY_MATCH_STATE,
+                LdapConstants.EQUALITY_MATCH_FILTER_TAG,
+                new InitEqualityMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to Substrings filter
@@ -6392,9 +5323,12 @@
         //     ...
         //
         // Init Substrings filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.SUBSTRING_FILTER_STATE,
-            LdapConstants.SUBSTRINGS_FILTER_TAG, new InitSubstringsFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.SUBSTRINGS_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.SUBSTRING_FILTER_STATE,
+                LdapConstants.SUBSTRINGS_FILTER_TAG,
+                new InitSubstringsFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to GreaterOrEqual filter
@@ -6410,9 +5344,12 @@
         //     ...
         //
         // Init Greater Or Equal filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.GREATER_OR_EQUAL_STATE,
-            LdapConstants.GREATER_OR_EQUAL_FILTER_TAG, new InitGreaterOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.GREATER_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.GREATER_OR_EQUAL_STATE,
+                LdapConstants.GREATER_OR_EQUAL_FILTER_TAG,
+                new InitGreaterOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to LessOrEqual filter
@@ -6428,9 +5365,12 @@
         //     ...
         //
         // Init Less Or Equal filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.LESS_OR_EQUAL_STATE,
-            LdapConstants.LESS_OR_EQUAL_FILTER_TAG, new InitLessOrEqualFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.LESS_OR_EQUAL_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.LESS_OR_EQUAL_STATE,
+                LdapConstants.LESS_OR_EQUAL_FILTER_TAG,
+                new InitLessOrEqualFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to Present filter
@@ -6446,9 +5386,12 @@
         //     ...
         //
         // Init present filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.PRESENT_STATE, LdapConstants.PRESENT_FILTER_TAG,
-            new InitPresentFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.PRESENT_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.PRESENT_STATE,
+                LdapConstants.PRESENT_FILTER_TAG,
+                new InitPresentFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to Approx Match filter
@@ -6464,9 +5407,12 @@
         //     ...
         //
         // Init Approx Match filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.APPROX_MATCH_STATE,
-            LdapConstants.APPROX_MATCH_FILTER_TAG, new InitApproxMatchFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.APPROX_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.APPROX_MATCH_STATE,
+                LdapConstants.APPROX_MATCH_FILTER_TAG,
+                new InitApproxMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to Extensible Match filter
@@ -6482,9 +5428,12 @@
         //     ...
         //
         // Init Assertion Value Filter filter
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
-            LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG, new InitExtensibleMatchFilterAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.EXTENSIBLE_MATCH_STATE,
+                LdapConstants.EXTENSIBLE_MATCH_FILTER_TAG,
+                new InitExtensibleMatchFilter() );
 
         // --------------------------------------------------------------------------------------------
         // Transition from dnAttributes to Attribute Description List
@@ -6498,47 +5447,23 @@
         //     AttributeDescription
         //
         // Init attribute description list
-        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
-            LdapStatesEnum.DN_ATTRIBUTES_STATE, LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
-            UniversalTag.SEQUENCE.getValue(), new InitAttributeDescListAction() );
+        super.transitions[LdapStatesEnum.DN_ATTRIBUTES_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition(
+                LdapStatesEnum.DN_ATTRIBUTES_STATE,
+                LdapStatesEnum.ATTRIBUTE_DESCRIPTION_LIST_STATE,
+                SEQUENCE,
+                new InitSearchRequestAttributeDescList() );
     }
 
 
-    // ~ Methods
-    // ------------------------------------------------------------------------------------
-
     /**
      * Get the instance of this grammar
-     * 
+     *
      * @return An instance on the LdapMessage Grammar
      */
+    @SuppressWarnings("rawtypes")
     public static Grammar getInstance()
     {
         return instance;
     }
-
-    /**
-     * Build an AttributeType froma byte array. An AttributeType contains
-     * only chars within [0-9][a-z][A-Z][-.].
-     *
-     * @param bytes The bytes containing the AttributeType
-     * @return The AttributeType as a String
-     */
-    public static String getType( byte[] bytes )
-    {
-        if ( bytes == null )
-        {
-            return null;
-        }
-
-        char[] chars = new char[bytes.length];
-        int pos = 0;
-
-        for ( byte b:bytes )
-        {
-            chars[pos++] = ( char ) b;
-        }
-
-        return new String( chars );
-    }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapStatesEnum.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapStatesEnum.java
index 95c68f2..2802d93 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapStatesEnum.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/LdapStatesEnum.java
@@ -6,20 +6,21 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.ldap.codec;
 
 
+import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.grammar.Grammar;
 import org.apache.directory.shared.asn1.ber.grammar.States;
 
@@ -27,14 +28,11 @@
 /**
  * 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
 {
-    // ~ Static fields/initializers
-    // -----------------------------------------------------------------
-
     /** The END_STATE */
     END_STATE,
 
@@ -155,10 +153,10 @@
     INTERMEDIATE_RESPONSE_VALUE_STATE,
     LAST_LDAP_STATE;
 
-    
+
     /**
      * Get the grammar name
-     * 
+     *
      * @param grammar
      *            The grammar code
      * @return The grammar name
@@ -171,12 +169,12 @@
 
     /**
      * Get the grammar name
-     * 
+     *
      * @param grammar
      *            The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<Asn1Container> grammar )
     {
         if ( grammar instanceof LdapMessageGrammar )
         {
@@ -191,7 +189,7 @@
 
     /**
      * Get the string representing the state
-     * 
+     *
      * @param state The state number
      * @return The String representing the state
      */
@@ -200,7 +198,7 @@
         return ( ( state == END_STATE.ordinal() ) ? "LDAP_MESSAGE_END_STATE" : name() );
     }
 
-    
+
     /**
      * {@inheritDoc}
      */
@@ -208,8 +206,8 @@
     {
         return this == END_STATE;
     }
-    
-    
+
+
     /**
      * {@inheritDoc}
      */
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/AllowGrammarEnd.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/AllowGrammarEnd.java
new file mode 100644
index 0000000..0da0e59
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlsInitAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/CheckLengthNotNull.java
similarity index 74%
copy from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlsInitAction.java
copy to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/CheckLengthNotNull.java
index 19a7192..7326a77 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlsInitAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/CheckLengthNotNull.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.ldap.codec.actions;
 
@@ -23,6 +23,7 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
 import org.apache.directory.shared.ldap.model.message.Message;
@@ -31,25 +32,21 @@
 
 
 /**
- * The action used to initialize a control.
- * 
+ * 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 ControlsInitAction extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class CheckLengthNotNull extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ControlsInitAction.class );
-
-    /** Speedup for logs */
-    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
-
+    private static final Logger LOG = LoggerFactory.getLogger( CheckLengthNotNull.class );
 
     /**
-     * Instantiates a new controls init action.
+     * Instantiates the action.
      */
-    public ControlsInitAction()
+    public CheckLengthNotNull()
     {
-        super( "Initialize a control" );
+        super( "Check that the length is not null" );
     }
 
 
@@ -64,15 +61,11 @@
         // The Length should be null
         if ( expectedLength == 0 )
         {
-            LOG.error( "The length of controls must not be null" );
+            String msg = I18n.err( I18n.ERR_04096 );
+            LOG.error( msg );
 
             // 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" );
+            throw new DecoderException( msg );
         }
     }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/abandonRequest/InitAbandonRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/abandonRequest/InitAbandonRequest.java
new file mode 100644
index 0000000..5b61e8f
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/abandonRequest/InitAbandonRequest.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.shared.ldap.codec.actions.abandonRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.AbandonRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.AbandonRequestImpl;
+import org.apache.directory.shared.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
+        AbandonRequestDecorator abandonRequest = new AbandonRequestDecorator(
+            container.getLdapCodecService(), new AbandonRequestImpl( container.getMessageId() ) );
+        container.setMessage( abandonRequest );
+
+        // The current TLV should be a integer
+        // We get it and store it in MessageId
+        TLV tlv = container.getCurrentTLV();
+
+        Value 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() );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/AddAddRequestAttributeType.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/AddAddRequestAttributeType.java
new file mode 100644
index 0000000..1da3c8a
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/AddAddRequestAttributeType.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.shared.ldap.codec.actions.addRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.ldap.model.message.AddResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ValueAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/AddAttributeValue.java
similarity index 85%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ValueAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/AddAttributeValue.java
index efd0b11..83d9856 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ValueAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/AddAttributeValue.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.addRequest;
 
 
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
@@ -31,13 +31,19 @@
 
 /**
  * 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 ValueAction extends GrammarAction<LdapMessageContainer<AddRequestDecorator>>
+public class AddAttributeValue extends GrammarAction<LdapMessageContainer<AddRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ValueAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( AddAttributeValue.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -46,7 +52,7 @@
     /**
      * Instantiates a new value action.
      */
-    public ValueAction()
+    public AddAttributeValue()
     {
         super( "Store a value" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/InitAddRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/InitAddRequest.java
new file mode 100644
index 0000000..9dcbecb
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/InitAddRequest.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.shared.ldap.codec.actions.addRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.shared.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();
+        AddRequestDecorator addRequest = new AddRequestDecorator(
+            container.getLdapCodecService(), new AddRequestImpl( messageId ) );
+        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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/StoreAddRequestEntryName.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/StoreAddRequestEntryName.java
new file mode 100644
index 0000000..7e502dd
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addRequest/StoreAddRequestEntryName.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.shared.ldap.codec.actions.addRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.AddRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.message.AddResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addResponse/InitAddResponse.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addResponse/InitAddResponse.java
new file mode 100644
index 0000000..c6965ce
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/addResponse/InitAddResponse.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.shared.ldap.codec.actions.addResponse;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.AddResponseDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/InitBindRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/InitBindRequest.java
new file mode 100644
index 0000000..cc3635f
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/InitBindRequest.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.shared.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.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
+        BindRequestDecorator bindRequest = new BindRequestDecorator(
+            container.getLdapCodecService(), new BindRequestImpl( container.getMessageId() ) );
+        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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/InitSaslBind.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/InitSaslBind.java
new file mode 100644
index 0000000..28c5d53
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.BindRequest;
+import org.apache.directory.shared.ldap.model.message.BindResponseImpl;
+import org.apache.directory.shared.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.getName(), null );
+        }
+
+        bindRequestMessage.setSimple( false );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The SaslCredential has been created" );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreName.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreName.java
new file mode 100644
index 0000000..44302da
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreName.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.shared.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.message.BindRequest;
+import org.apache.directory.shared.ldap.model.message.BindResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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( Dn.EMPTY_DN );
+        }
+        else
+        {
+            byte[] dnBytes = tlv.getValue().getData();
+            String dnStr = Strings.utf8ToString(dnBytes);
+
+            try
+            {
+                Dn dn = new Dn( dnStr );
+                bindRequestMessage.setName( dn );
+            }
+            catch ( LdapInvalidDnException ine )
+            {
+                String msg = "Incorrect Dn given : " + dnStr + " (" + Strings.dumpBytes(dnBytes)
+                    + ") 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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ServerSASLCredsAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreSaslCredentials.java
similarity index 61%
copy from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ServerSASLCredsAction.java
copy to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreSaslCredentials.java
index 5a9fe30..231dfee 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ServerSASLCredsAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreSaslCredentials.java
@@ -6,26 +6,26 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.bindRequest;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
-import org.apache.directory.shared.ldap.codec.decorators.BindResponseDecorator;
-import org.apache.directory.shared.ldap.model.message.BindResponse;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.BindRequest;
 import org.apache.directory.shared.util.StringConstants;
 import org.apache.directory.shared.util.Strings;
 import org.slf4j.Logger;
@@ -33,58 +33,60 @@
 
 
 /**
- * The action used to store a SASL credentials
- * 
+ * 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 ServerSASLCredsAction extends GrammarAction<LdapMessageContainer<BindResponseDecorator>>
+public class StoreSaslCredentials extends GrammarAction<LdapMessageContainer<BindRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ServerSASLCredsAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSaslCredentials.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
 
     /**
-     * Instantiates a new server sasl creds action.
+     * Instantiates a new action.
      */
-    public ServerSASLCredsAction()
+    public StoreSaslCredentials()
     {
-        super( "Store server sasl credentials value" );
+        super( "Store SASL credentials" );
     }
 
 
     /**
      * {@inheritDoc}
      */
-    public void action( LdapMessageContainer<BindResponseDecorator> container ) throws DecoderException
+    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 server
-        // sasl credentials
-        byte[] serverSaslCreds = null;
-
+        // We have to handle the special case of a 0 length
+        // credentials
         if ( tlv.getLength() == 0 )
         {
-            serverSaslCreds = StringConstants.EMPTY_BYTES;
+            bindRequestMessage.setCredentials( StringConstants.EMPTY_BYTES );
         }
         else
         {
-            serverSaslCreds = tlv.getValue().getData();
+            bindRequestMessage.setCredentials( 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) );
+            LOG.debug( "The credentials are : {}", Strings.dumpBytes(bindRequestMessage
+                    .getCredentials()) );
         }
     }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreSaslMechanism.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreSaslMechanism.java
new file mode 100644
index 0000000..3265335
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.BindRequest;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreSimpleAuth.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreSimpleAuth.java
new file mode 100644
index 0000000..518bdda
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.BindRequest;
+import org.apache.directory.shared.util.StringConstants;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreVersion.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindRequest/StoreVersion.java
new file mode 100644
index 0000000..fa3d3a5
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.bindRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.BindRequest;
+import org.apache.directory.shared.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();
+
+        Value 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() );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindResponse/InitBindResponse.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindResponse/InitBindResponse.java
new file mode 100644
index 0000000..11ccece
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.bindResponse;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.BindResponseDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ServerSASLCredsAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindResponse/StoreServerSASLCreds.java
similarity index 85%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ServerSASLCredsAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindResponse/StoreServerSASLCreds.java
index 5a9fe30..1aa7531 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ServerSASLCredsAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/bindResponse/StoreServerSASLCreds.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.bindResponse;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -33,14 +33,18 @@
 
 
 /**
- * The action used to store a SASL credentials
- * 
+ * 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 ServerSASLCredsAction extends GrammarAction<LdapMessageContainer<BindResponseDecorator>>
+public class StoreServerSASLCreds extends GrammarAction<LdapMessageContainer<BindResponseDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ServerSASLCredsAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreServerSASLCreds.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -49,7 +53,7 @@
     /**
      * Instantiates a new server sasl creds action.
      */
-    public ServerSASLCredsAction()
+    public StoreServerSASLCreds()
     {
         super( "Store server sasl credentials value" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/InitCompareRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/InitCompareRequest.java
new file mode 100644
index 0000000..7c84461
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/InitCompareRequest.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.shared.ldap.codec.actions.compareRequest;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.shared.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
+        CompareRequestDecorator compareRequest = new CompareRequestDecorator(
+            container.getLdapCodecService(), new CompareRequestImpl( container.getMessageId() ) );
+        container.setMessage( compareRequest );
+
+        LOG.debug( "Compare Request" );
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/StoreCompareRequestAssertionValue.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/StoreCompareRequestAssertionValue.java
new file mode 100644
index 0000000..57034a3
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/StoreCompareRequestAssertionValue.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.shared.ldap.codec.actions.compareRequest;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.CompareRequest;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/StoreCompareRequestAttributeDesc.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/StoreCompareRequestAttributeDesc.java
new file mode 100644
index 0000000..028ac4f
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/StoreCompareRequestAttributeDesc.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.shared.ldap.codec.actions.compareRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.CompareRequest;
+import org.apache.directory.shared.ldap.model.message.CompareResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/StoreCompareRequestEntryName.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/StoreCompareRequestEntryName.java
new file mode 100644
index 0000000..f3adce1
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareRequest/StoreCompareRequestEntryName.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.shared.ldap.codec.actions.compareRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.message.CompareRequest;
+import org.apache.directory.shared.ldap.model.message.CompareResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareResponse/InitCompareResponse.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareResponse/InitCompareResponse.java
new file mode 100644
index 0000000..cbbe20b
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/compareResponse/InitCompareResponse.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.shared.ldap.codec.actions.compareResponse;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.CompareResponseDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/AddControl.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/AddControl.java
new file mode 100644
index 0000000..2f703d0
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.controls;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.util.OID;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlsInitAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/InitControls.java
similarity index 85%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlsInitAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/InitControls.java
index 19a7192..7055b92 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlsInitAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/InitControls.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.controls;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -32,13 +32,16 @@
 
 /**
  * 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 ControlsInitAction extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class InitControls extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ControlsInitAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitControls.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -47,7 +50,7 @@
     /**
      * Instantiates a new controls init action.
      */
-    public ControlsInitAction()
+    public InitControls()
     {
         super( "Initialize a control" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/StoreControlCriticality.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/StoreControlCriticality.java
new file mode 100644
index 0000000..f6f890e
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.controls;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.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.
+        Value 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() );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Control criticality : " + control.isCritical() );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlValueAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/StoreControlValue.java
similarity index 81%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlValueAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/StoreControlValue.java
index 4631973..988d943 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlValueAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/controls/StoreControlValue.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.controls;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -39,19 +39,33 @@
  * 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 ControlValueAction extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class StoreControlValue extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ControlValueAction.class );
+    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
@@ -84,7 +98,7 @@
 
         if ( IS_DEBUG )
         {
-            LOG.debug( "Control value : " + Strings.dumpBytes((byte[]) control.getValue()) );
+            LOG.debug( "Control value : " + Strings.dumpBytes(control.getValue()) );
         }
     }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/delRequest/InitDelRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/delRequest/InitDelRequest.java
new file mode 100644
index 0000000..63ec443
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/delRequest/InitDelRequest.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.shared.ldap.codec.actions.delRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.DeleteRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.message.DeleteRequestImpl;
+import org.apache.directory.shared.ldap.model.message.DeleteResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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
+        DeleteRequestDecorator delRequest = new DeleteRequestDecorator(
+            container.getLdapCodecService(), new DeleteRequestImpl( container.getMessageId() ) );
+        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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/delResponse/InitDelResponse.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/delResponse/InitDelResponse.java
new file mode 100644
index 0000000..0b0f1fc
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/delResponse/InitDelResponse.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.shared.ldap.codec.actions.delResponse;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.DeleteResponseDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedRequest/InitExtendedRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedRequest/InitExtendedRequest.java
new file mode 100644
index 0000000..eb77ef9
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedRequest/InitExtendedRequest.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.shared.ldap.codec.actions.extendedRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.ExtendedRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.ExtendedRequestImpl;
+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
+    {
+        // Now, we can allocate the ExtendedRequest Object
+        ExtendedRequestDecorator extendedRequest = new ExtendedRequestDecorator(
+            container.getLdapCodecService(), new ExtendedRequestImpl( container.getMessageId() ) );
+        container.setMessage( extendedRequest );
+
+        LOG.debug( "Extended request" );
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedRequest/StoreExtendedRequestName.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedRequest/StoreExtendedRequestName.java
new file mode 100644
index 0000000..ee2f2eb
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedRequest/StoreExtendedRequestName.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.shared.ldap.codec.actions.extendedRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.util.OID;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.ExtendedRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
+import org.apache.directory.shared.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
+    {
+        // We can allocate the ExtendedRequest Object
+        ExtendedRequest 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
+        // 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 );
+                }
+
+                extendedRequest.setRequestName( requestName );
+            }
+            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 : {}", extendedRequest.getRequestName() );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResponseAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedRequest/StoreExtendedRequestValue.java
similarity index 61%
copy from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResponseAction.java
copy to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedRequest/StoreExtendedRequestValue.java
index 42d1d64..ca37da7 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResponseAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedRequest/StoreExtendedRequestValue.java
@@ -6,74 +6,77 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.extendedRequest;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
-import org.apache.directory.shared.ldap.codec.decorators.ExtendedResponseDecorator;
-import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
+import org.apache.directory.shared.ldap.codec.decorators.ExtendedRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
 import org.apache.directory.shared.util.StringConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 
 /**
- * The action used to store a Response to an ExtendedResponse
- * 
+ * 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 ResponseAction extends GrammarAction<LdapMessageContainer<ExtendedResponseDecorator>>
+public class StoreExtendedRequestValue extends GrammarAction<LdapMessageContainer<ExtendedRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ResponseAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreExtendedRequestValue.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
-
     /**
-     * Instantiates a new response action.
+     * Instantiates a new action.
      */
-    public ResponseAction()
+    public StoreExtendedRequestValue()
     {
-        super( "Store response" );
+        super( "Store ExtendedRequest value" );
     }
 
 
     /**
      * {@inheritDoc}
      */
-    public void action( LdapMessageContainer<ExtendedResponseDecorator> container ) throws DecoderException
+    public void action( LdapMessageContainer<ExtendedRequestDecorator> container ) throws DecoderException
     {
-        // We can allocate the ExtendedResponse Object
-        ExtendedResponse extendedResponse = container.getMessage();
+        // We can allocate the ExtendedRequest Object
+        ExtendedRequest extendedRequest = container.getMessage();
 
-        // Get the Value and store it in the ExtendedResponse
+        // 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
+        // value
         if ( tlv.getLength() == 0 )
         {
-            extendedResponse.setResponseValue( StringConstants.EMPTY_BYTES );
+            extendedRequest.setRequestValue( StringConstants.EMPTY_BYTES );
         }
         else
         {
-            extendedResponse.setResponseValue( tlv.getValue().getData() );
+            extendedRequest.setRequestValue( tlv.getValue().getData() );
         }
 
         // We can have an END transition
@@ -81,7 +84,7 @@
 
         if ( IS_DEBUG )
         {
-            LOG.debug( "Extended value : {}", extendedResponse.getResponseValue() );
+            LOG.debug( "Extended value : {}", extendedRequest.getRequestValue() );
         }
     }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedResponse/InitExtendedResponse.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedResponse/InitExtendedResponse.java
new file mode 100644
index 0000000..7dee8f0
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedResponse/InitExtendedResponse.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.shared.ldap.codec.actions.extendedResponse;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.ExtendedResponseDecorator;
+import org.apache.directory.shared.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(
+            container.getLdapCodecService(), new ExtendedResponseImpl( container.getMessageId() ) );
+        container.setMessage( extendedResponse );
+
+        LOG.debug( "Extended Response" );
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResponseAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedResponse/StoreExtendedResponseValue.java
similarity index 82%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResponseAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedResponse/StoreExtendedResponseValue.java
index 42d1d64..26b605d 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResponseAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedResponse/StoreExtendedResponseValue.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.extendedResponse;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -33,13 +33,17 @@
 
 /**
  * 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 ResponseAction extends GrammarAction<LdapMessageContainer<ExtendedResponseDecorator>>
+public class StoreExtendedResponseValue extends GrammarAction<LdapMessageContainer<ExtendedResponseDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ResponseAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreExtendedResponseValue.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -48,9 +52,9 @@
     /**
      * Instantiates a new response action.
      */
-    public ResponseAction()
+    public StoreExtendedResponseValue()
     {
-        super( "Store response" );
+        super( "Store response value" );
     }
 
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResponseNameAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedResponse/StoreResponseName.java
similarity index 83%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResponseNameAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedResponse/StoreResponseName.java
index 4c9a5ac..4285e9f 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResponseNameAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/extendedResponse/StoreResponseName.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.extendedResponse;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -35,13 +35,19 @@
 
 /**
  * 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 ResponseNameAction extends GrammarAction<LdapMessageContainer<ExtendedResponseDecorator>>
+public class StoreResponseName extends GrammarAction<LdapMessageContainer<ExtendedResponseDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ResponseNameAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreResponseName.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -50,7 +56,7 @@
     /**
      * Instantiates a new response name action.
      */
-    public ResponseNameAction()
+    public StoreResponseName()
     {
         super( "Store response name" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/intermediateResponse/InitIntermediateResponse.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/intermediateResponse/InitIntermediateResponse.java
new file mode 100644
index 0000000..f9ec476
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/intermediateResponse/InitIntermediateResponse.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.shared.ldap.codec.actions.intermediateResponse;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseName.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseName.java
new file mode 100644
index 0000000..40840a6
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.intermediateResponse;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.util.OID;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.shared.ldap.model.message.IntermediateResponse;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseValue.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/intermediateResponse/StoreIntermediateResponseValue.java
new file mode 100644
index 0000000..4ba5e45
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.intermediateResponse;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.shared.ldap.model.message.IntermediateResponse;
+import org.apache.directory.shared.util.StringConstants;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlsInitAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapMessage/InitLdapMessage.java
similarity index 63%
copy from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlsInitAction.java
copy to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapMessage/InitLdapMessage.java
index 19a7192..30f8155 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ControlsInitAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapMessage/InitLdapMessage.java
@@ -6,23 +6,24 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.ldapMessage;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
 import org.apache.directory.shared.ldap.model.message.Message;
@@ -31,25 +32,27 @@
 
 
 /**
- * The action used to initialize a control.
- * 
+ * 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 ControlsInitAction extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class InitLdapMessage extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ControlsInitAction.class );
-
-    /** Speedup for logs */
-    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
-
+    private static final Logger LOG = LoggerFactory.getLogger( InitLdapMessage.class );
 
     /**
-     * Instantiates a new controls init action.
+     * Instantiates a new action.
      */
-    public ControlsInitAction()
+    public InitLdapMessage()
     {
-        super( "Initialize a control" );
+        super( "LdapMessage initialization" );
     }
 
 
@@ -59,20 +62,14 @@
     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 )
+        // The Length should not be null
+        if ( tlv.getLength() == 0 )
         {
-            LOG.error( "The length of controls must not be null" );
+            LOG.error( I18n.err( I18n.ERR_04066 ) );
 
             // 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" );
+            throw new DecoderException( I18n.err( I18n.ERR_04067 ) );
         }
     }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapMessage/StoreMessageId.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapMessage/StoreMessageId.java
new file mode 100644
index 0000000..38d9b15
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.ldapMessage;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.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 ) );
+        }
+
+        Value 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() );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ReferralAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/AddReferral.java
similarity index 83%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ReferralAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/AddReferral.java
index 6f993e9..df4c0bd 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ReferralAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/AddReferral.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.ldapResult;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -27,8 +27,12 @@
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
 import org.apache.directory.shared.ldap.model.exception.LdapURLEncodingException;
-import org.apache.directory.shared.ldap.model.message.*;
 import org.apache.directory.shared.ldap.model.filter.LdapURL;
+import org.apache.directory.shared.ldap.model.message.LdapResult;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.Referral;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.message.ResultResponse;
 import org.apache.directory.shared.util.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,13 +40,16 @@
 
 /**
  * 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 ReferralAction extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class AddReferral extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ReferralAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( AddReferral.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -51,7 +58,7 @@
     /**
      * Instantiates a new referral action.
      */
-    public ReferralAction()
+    public AddReferral()
     {
         super( "Add a referral" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitReferralsAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/InitReferrals.java
similarity index 86%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitReferralsAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/InitReferrals.java
index 3d93401..45c9200 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitReferralsAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/InitReferrals.java
@@ -6,23 +6,23 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.ldapResult;
 
 
+import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
-import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
@@ -36,14 +36,18 @@
 
 
 /**
- * The action used to init referrals to a LdapTresult
- * 
+ * 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 InitReferralsAction extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class InitReferrals extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitReferralsAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitReferrals.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -52,7 +56,7 @@
     /**
      * Instantiates a new init referrals action.
      */
-    public InitReferralsAction()
+    public InitReferrals()
     {
         super( "Init the referrals list" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ErrorMessageAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/StoreErrorMessage.java
similarity index 85%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ErrorMessageAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/StoreErrorMessage.java
index dd1c06a..1218e87 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ErrorMessageAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/StoreErrorMessage.java
@@ -6,23 +6,23 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.ldapResult;
 
 
+import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
-import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
 import org.apache.directory.shared.ldap.model.message.LdapResult;
@@ -35,13 +35,19 @@
 
 /**
  * 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 ErrorMessageAction extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class StoreErrorMessage extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ErrorMessageAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreErrorMessage.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -50,7 +56,7 @@
     /**
      * Instantiates a new error message action.
      */
-    public ErrorMessageAction()
+    public StoreErrorMessage()
     {
         super( "Store error message" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/MatchedDNAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/StoreMatchedDN.java
similarity index 90%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/MatchedDNAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/StoreMatchedDN.java
index 7d0040d..f49f9da 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/MatchedDNAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/StoreMatchedDN.java
@@ -6,23 +6,23 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.ldapResult;
 
 
+import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
-import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
@@ -39,13 +39,19 @@
 
 /**
  * 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 MatchedDNAction extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class StoreMatchedDN extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( MatchedDNAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreMatchedDN.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -54,7 +60,7 @@
     /**
      * Instantiates a new matched dn action.
      */
-    public MatchedDNAction()
+    public StoreMatchedDN()
     {
         super( "Store matched Dn" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResultCodeAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/StoreResultCode.java
similarity index 91%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResultCodeAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/StoreResultCode.java
index ae28f64..18286da 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ResultCodeAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ldapResult/StoreResultCode.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.ldapResult;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -40,13 +40,17 @@
 
 /**
  * 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 ResultCodeAction extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class StoreResultCode extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ResultCodeAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreResultCode.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -55,7 +59,7 @@
     /**
      * Instantiates a new result code action.
      */
-    public ResultCodeAction()
+    public StoreResultCode()
     {
         super( "Store resultCode" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/InitModifyDnRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/InitModifyDnRequest.java
new file mode 100644
index 0000000..f98db22
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/InitModifyDnRequest.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.shared.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.shared.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
+        ModifyDnRequestDecorator modifyDnRequest = new ModifyDnRequestDecorator(
+            container.getLdapCodecService(), new ModifyDnRequestImpl( container.getMessageId() ) );
+        container.setMessage( modifyDnRequest );
+
+        LOG.debug( "ModifyDn request" );
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestDeleteOldRdn.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestDeleteOldRdn.java
new file mode 100644
index 0000000..6aed614
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestDeleteOldRdn.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.shared.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.shared.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.
+        Value 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() );
+        }
+
+        // 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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestEntryName.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestEntryName.java
new file mode 100644
index 0000000..ad0ce4d
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestEntryName.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.shared.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.shared.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewRdn.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewRdn.java
new file mode 100644
index 0000000..9fa1058
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewRdn.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.shared.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.shared.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.name.Rdn;
+import org.apache.directory.shared.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( 0 );
+            }
+            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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewSuperior.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewSuperior.java
new file mode 100644
index 0000000..6de3fa0
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnRequest/StoreModifyDnRequestNewSuperior.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.shared.ldap.codec.actions.modifyDnRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.message.ModifyDnRequest;
+import org.apache.directory.shared.ldap.model.message.ModifyDnResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnResponse/InitModifyDnResponse.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnResponse/InitModifyDnResponse.java
new file mode 100644
index 0000000..9b173b3
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyDnResponse/InitModifyDnResponse.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.shared.ldap.codec.actions.modifyDnResponse;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyDnResponseDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/AddModifyRequestAttribute.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/AddModifyRequestAttribute.java
new file mode 100644
index 0000000..fec0f09
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/AddModifyRequestAttribute.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.shared.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.ModifyRequest;
+import org.apache.directory.shared.ldap.model.message.ModifyResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/InitAttributeVals.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/InitAttributeVals.java
new file mode 100644
index 0000000..4220f7a
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/InitAttributeVals.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.shared.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/InitModifyRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/InitModifyRequest.java
new file mode 100644
index 0000000..1470b6e
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/InitModifyRequest.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.shared.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.ModifyRequest;
+import org.apache.directory.shared.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 modifyRequest = new ModifyRequestImpl( container.getMessageId() );
+        ModifyRequestDecorator modifyRequestDecorator = new ModifyRequestDecorator(
+            container.getLdapCodecService(), modifyRequest );
+        container.setMessage( modifyRequestDecorator );
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ModifyAttributeValueAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/StoreModifyRequestAttributeValue.java
similarity index 88%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ModifyAttributeValueAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/StoreModifyRequestAttributeValue.java
index eb34193..34243d7 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/ModifyAttributeValueAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/StoreModifyRequestAttributeValue.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.modifyRequest;
 
 
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
@@ -35,10 +35,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class ModifyAttributeValueAction extends GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>
+public class StoreModifyRequestAttributeValue extends GrammarAction<LdapMessageContainer<ModifyRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( ModifyAttributeValueAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreModifyRequestAttributeValue.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -47,7 +47,7 @@
     /**
      * Instantiates a new modify attribute value action.
      */
-    public ModifyAttributeValueAction()
+    public StoreModifyRequestAttributeValue()
     {
         super( "Stores AttributeValue" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/StoreModifyRequestObjectName.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/StoreModifyRequestObjectName.java
new file mode 100644
index 0000000..64ff082
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/StoreModifyRequestObjectName.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.shared.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.message.ModifyRequest;
+import org.apache.directory.shared.ldap.model.message.ModifyResponseImpl;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/StoreOperationType.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/StoreOperationType.java
new file mode 100644
index 0000000..5b4561d
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyRequest/StoreOperationType.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.shared.ldap.codec.actions.modifyRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.LdapConstants;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.shared.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 );
+        }
+
+        // Store the current operation.
+        modifyRequestDecorator.setCurrentOperation( operation );
+
+        if ( IS_DEBUG )
+        {
+            switch ( operation )
+            {
+                case LdapConstants.OPERATION_ADD:
+                    LOG.debug( "Modification operation : ADD" );
+                    break;
+
+                case LdapConstants.OPERATION_DELETE:
+                    LOG.debug( "Modification operation : DELETE" );
+                    break;
+
+                case LdapConstants.OPERATION_REPLACE:
+                    LOG.debug( "Modification operation : REPLACE" );
+                    break;
+            }
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyResponse/InitModifyResponse.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyResponse/InitModifyResponse.java
new file mode 100644
index 0000000..6f2280d
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/modifyResponse/InitModifyResponse.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.shared.ldap.codec.actions.modifyResponse;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.ModifyResponseDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/InitSearchRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/InitSearchRequest.java
new file mode 100644
index 0000000..4b2fa72
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/InitSearchRequest.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.shared.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.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();
+
+        SearchRequestDecorator searchRequest = new SearchRequestDecorator(
+            container.getLdapCodecService(), new SearchRequestImpl( container.getMessageId() ) );
+
+        searchRequest.setTlvId( tlv.getId());
+        container.setMessage( searchRequest );
+
+        LOG.debug( "Search Request" );
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAttributeDescListAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/InitSearchRequestAttributeDescList.java
similarity index 80%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAttributeDescListAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/InitSearchRequestAttributeDescList.java
index 7c461cc..2164ab5 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAttributeDescListAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/InitSearchRequestAttributeDescList.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -31,13 +31,21 @@
 
 /**
  * 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 InitAttributeDescListAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitSearchRequestAttributeDescList extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitAttributeDescListAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitSearchRequestAttributeDescList.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -45,7 +53,7 @@
     /**
      * Instantiates a new init attribute desc list action.
      */
-    public InitAttributeDescListAction()
+    public InitSearchRequestAttributeDescList()
     {
         super( "Initialize AttributeDesc list" );
     }
@@ -58,9 +66,9 @@
         // 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 );
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/AttributeDescAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestAttributeDesc.java
similarity index 81%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/AttributeDescAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestAttributeDesc.java
index 0df8864..f5eba8c 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/AttributeDescAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestAttributeDesc.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -32,22 +32,28 @@
 
 /**
  * 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 AttributeDescAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class StoreSearchRequestAttributeDesc extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( AttributeDescAction.class );
+    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 AttributeDescAction()
+    public StoreSearchRequestAttributeDesc()
     {
         super( "Store attribute description" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestBaseObject.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestBaseObject.java
new file mode 100644
index 0000000..f535e6d
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.model.message.SearchRequest;
+import org.apache.directory.shared.ldap.model.message.SearchResultDoneImpl;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestDerefAlias.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestDerefAlias.java
new file mode 100644
index 0000000..4130a7f
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestDerefAlias.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.shared.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.LdapConstants;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.AliasDerefMode;
+import org.apache.directory.shared.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
+        Value value = tlv.getValue();
+        int derefAliases = 0;
+
+        try
+        {
+            derefAliases = IntegerDecoder.parse(value, LdapConstants.NEVER_DEREF_ALIASES,
+                    LdapConstants.DEREF_ALWAYS);
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            String msg = I18n.err( I18n.ERR_04102, value.toString() );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        searchRequest.setDerefAliases( AliasDerefMode.getDerefMode( derefAliases ) );
+
+        if ( IS_DEBUG )
+        {
+            switch ( derefAliases )
+            {
+                case LdapConstants.NEVER_DEREF_ALIASES:
+                    LOG.debug( "Handling object strategy : NEVER_DEREF_ALIASES" );
+                    break;
+
+                case LdapConstants.DEREF_IN_SEARCHING:
+                    LOG.debug( "Handling object strategy : DEREF_IN_SEARCHING" );
+                    break;
+
+                case LdapConstants.DEREF_FINDING_BASE_OBJ:
+                    LOG.debug( "Handling object strategy : DEREF_FINDING_BASE_OBJ" );
+                    break;
+
+                case LdapConstants.DEREF_ALWAYS:
+                    LOG.debug( "Handling object strategy : DEREF_ALWAYS" );
+                    break;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestScope.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestScope.java
new file mode 100644
index 0000000..fc7808b
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestScope.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.shared.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.LdapConstants;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.model.filter.SearchScope;
+import org.apache.directory.shared.ldap.model.message.SearchRequest;
+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
+        Value value = tlv.getValue();
+        int scope = 0;
+
+        try
+        {
+            scope = IntegerDecoder.parse( value, LdapConstants.SCOPE_BASE_OBJECT,
+                LdapConstants.SCOPE_WHOLE_SUBTREE );
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            String msg = I18n.err( I18n.ERR_04101, value.toString() );
+            LOG.error( msg );
+            throw new DecoderException( msg );
+        }
+
+        searchRequest.setScope( SearchScope.getSearchScope(scope) );
+
+        if ( IS_DEBUG )
+        {
+            switch ( scope )
+            {
+                case LdapConstants.SCOPE_BASE_OBJECT:
+                    LOG.debug( "Searching within BASE_OBJECT scope " );
+                    break;
+
+                case LdapConstants.SCOPE_SINGLE_LEVEL:
+                    LOG.debug( "Searching within SINGLE_LEVEL scope " );
+                    break;
+
+                case LdapConstants.SCOPE_WHOLE_SUBTREE:
+                    LOG.debug( "Searching within WHOLE_SUBTREE scope " );
+                    break;
+            }
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestSizeLimit.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestSizeLimit.java
new file mode 100644
index 0000000..e9145d2
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestSizeLimit.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.shared.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.LongDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.LongDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.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
+        Value 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 );
+        }
+
+        searchRequest.setSizeLimit( sizeLimit );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The sizeLimit value is set to {} objects", Long.valueOf( sizeLimit ) );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestTimeLimit.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestTimeLimit.java
new file mode 100644
index 0000000..0b3f41f
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestTimeLimit.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.shared.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.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
+        Value 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 );
+        }
+
+        searchRequest.setTimeLimit( timeLimit );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The timeLimit value is set to {} seconds", Integer.valueOf( timeLimit ) );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestTypesOnly.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestTypesOnly.java
new file mode 100644
index 0000000..ab516df
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreSearchRequestTypesOnly.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.shared.ldap.codec.actions.searchRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.model.message.SearchRequest;
+import org.apache.directory.shared.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.
+        Value 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() );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "The search will return {}", ( searchRequest.getTypesOnly() ? "only attributs type"
+                : "attributes types and values" ) );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreTypeMatchingRuleAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreTypeMatchingRule.java
similarity index 91%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreTypeMatchingRuleAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreTypeMatchingRule.java
index ed5939b..f18ba82 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreTypeMatchingRuleAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/StoreTypeMatchingRule.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -37,11 +37,11 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class StoreTypeMatchingRuleAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class StoreTypeMatchingRule extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
 
     /** The logger. */
-    private static final Logger LOG = LoggerFactory.getLogger( StoreTypeMatchingRuleAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreTypeMatchingRule.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -50,7 +50,7 @@
     /**
      * Instantiates a new store type matching rule action.
      */
-    public StoreTypeMatchingRuleAction()
+    public StoreTypeMatchingRule()
     {
         super( "Store matching type Value" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAndFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitAndFilter.java
similarity index 91%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAndFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitAndFilter.java
index 25dc33f..fd9c416 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAndFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitAndFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -37,10 +37,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitAndFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitAndFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitAndFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitAndFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -49,7 +49,7 @@
     /**
      * Instantiates a new init AND filter action.
      */
-    public InitAndFilterAction()
+    public InitAndFilter()
     {
         super( "Initialize AND filter" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitApproxMatchFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitApproxMatchFilter.java
similarity index 90%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitApproxMatchFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitApproxMatchFilter.java
index e7319ca..da1cfd0 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitApproxMatchFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitApproxMatchFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -36,10 +36,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitApproxMatchFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitApproxMatchFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitApproxMatchFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitApproxMatchFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -48,7 +48,7 @@
     /**
      * Instantiates a new init approx match filter action.
      */
-    public InitApproxMatchFilterAction()
+    public InitApproxMatchFilter()
     {
         super( "Init Approx Match filter Value" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAssertionValueFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitAssertionValueFilter.java
similarity index 93%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAssertionValueFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitAssertionValueFilter.java
index 81eb841..632e981 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAssertionValueFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitAssertionValueFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -41,10 +41,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitAssertionValueFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitAssertionValueFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitAssertionValueFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitAssertionValueFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -53,7 +53,7 @@
     /**
      * Instantiates a new init assertion value filter action.
      */
-    public InitAssertionValueFilterAction()
+    public InitAssertionValueFilter()
     {
         super( "Initialize Assertion Value filter" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAttributeDescFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitAttributeDescFilter.java
similarity index 91%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAttributeDescFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitAttributeDescFilter.java
index 12fb267..47a761d 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitAttributeDescFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitAttributeDescFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -38,10 +38,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitAttributeDescFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitAttributeDescFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitAttributeDescFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitAttributeDescFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -50,7 +50,7 @@
     /**
      * Instantiates a new init attribute desc filter action.
      */
-    public InitAttributeDescFilterAction()
+    public InitAttributeDescFilter()
     {
         super( "Initialize AttributeDesc filter" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitEqualityMatchFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitEqualityMatchFilter.java
similarity index 90%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitEqualityMatchFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitEqualityMatchFilter.java
index 2258e62..bc1fbab 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitEqualityMatchFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitEqualityMatchFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -36,10 +36,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitEqualityMatchFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitEqualityMatchFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitEqualityMatchFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitEqualityMatchFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -48,7 +48,7 @@
     /**
      * Instantiates a new init equality match filter action.
      */
-    public InitEqualityMatchFilterAction()
+    public InitEqualityMatchFilter()
     {
         super( "Initialize Equality Match filter" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitExtensibleMatchFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitExtensibleMatchFilter.java
similarity index 89%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitExtensibleMatchFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitExtensibleMatchFilter.java
index 23968e1..07818f7 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitExtensibleMatchFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitExtensibleMatchFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
@@ -36,10 +36,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitExtensibleMatchFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitExtensibleMatchFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitExtensibleMatchFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitExtensibleMatchFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -48,7 +48,7 @@
     /**
      * Instantiates a new init extensible match filter action.
      */
-    public InitExtensibleMatchFilterAction()
+    public InitExtensibleMatchFilter()
     {
         super( "Init Extensible Match filter Value" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitGreaterOrEqualFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitGreaterOrEqualFilter.java
similarity index 90%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitGreaterOrEqualFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitGreaterOrEqualFilter.java
index 70665d8..0cb7b07 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitGreaterOrEqualFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitGreaterOrEqualFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -36,10 +36,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitGreaterOrEqualFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitGreaterOrEqualFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitGreaterOrEqualFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitGreaterOrEqualFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -48,7 +48,7 @@
     /**
      * Instantiates a new init greater or equal filter action.
      */
-    public InitGreaterOrEqualFilterAction()
+    public InitGreaterOrEqualFilter()
     {
         super( "Initialize Greater Or Equal filter" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitLessOrEqualFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitLessOrEqualFilter.java
similarity index 90%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitLessOrEqualFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitLessOrEqualFilter.java
index 706d5ac..06e2e29 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitLessOrEqualFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitLessOrEqualFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -36,10 +36,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitLessOrEqualFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitLessOrEqualFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitLessOrEqualFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitLessOrEqualFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -48,7 +48,7 @@
     /**
      * Instantiates a new init less or equal filter action.
      */
-    public InitLessOrEqualFilterAction()
+    public InitLessOrEqualFilter()
     {
         super( "Initialize Less Or Equal filter" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitNotFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitNotFilter.java
similarity index 91%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitNotFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitNotFilter.java
index 37f44b7..bdc13f2 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitNotFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitNotFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -37,10 +37,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitNotFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitNotFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitNotFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitNotFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -49,7 +49,7 @@
     /**
      * Instantiates a new init NOT filter action.
      */
-    public InitNotFilterAction()
+    public InitNotFilter()
     {
         super( "Initialize NOT filter" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitOrFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitOrFilter.java
similarity index 91%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitOrFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitOrFilter.java
index a32fa45..563648f 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitOrFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitOrFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
@@ -38,10 +38,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitOrFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitOrFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitOrFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitOrFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -50,7 +50,7 @@
     /**
      * Instantiates a new init OR filter action.
      */
-    public InitOrFilterAction()
+    public InitOrFilter()
     {
         super( "Initialize OR filter" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitPresentFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitPresentFilter.java
similarity index 92%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitPresentFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitPresentFilter.java
index 15c2258..ed48c11 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitPresentFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitPresentFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
@@ -37,10 +37,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitPresentFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitPresentFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitPresentFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitPresentFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -49,7 +49,7 @@
     /**
      * Instantiates a new init present filter action.
      */
-    public InitPresentFilterAction()
+    public InitPresentFilter()
     {
         super( "Init present filter Value" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitSubstringsFilterAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitSubstringsFilter.java
similarity index 91%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitSubstringsFilterAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitSubstringsFilter.java
index bb71c6c..13332a8 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/InitSubstringsFilterAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/InitSubstringsFilter.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -37,10 +37,10 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class InitSubstringsFilterAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class InitSubstringsFilter extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( InitSubstringsFilterAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( InitSubstringsFilter.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -49,7 +49,7 @@
     /**
      * Instantiates a new init substrings filter action.
      */
-    public InitSubstringsFilterAction()
+    public InitSubstringsFilter()
     {
         super( "Initialize Substrings filter" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreAnyAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreAny.java
similarity index 86%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreAnyAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreAny.java
index 57664a1..9b24e69 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreAnyAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreAny.java
@@ -6,23 +6,23 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
+import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
-import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
@@ -34,13 +34,20 @@
 
 /**
  * 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 StoreAnyAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class StoreAny extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( StoreAnyAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreAny.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -49,7 +56,7 @@
     /**
      * Instantiates a new store any action.
      */
-    public StoreAnyAction()
+    public StoreAny()
     {
         super( "Store a any value" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreFinalAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreFinal.java
similarity index 86%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreFinalAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreFinal.java
index 4a9c1b0..9a4a518 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreFinalAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreFinal.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -27,7 +27,6 @@
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
 import org.apache.directory.shared.ldap.codec.search.SubstringFilter;
-
 import org.apache.directory.shared.util.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,13 +34,20 @@
 
 /**
  * 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 StoreFinalAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class StoreFinal extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( StoreFinalAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreFinal.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -50,7 +56,7 @@
     /**
      * Instantiates a new store final action.
      */
-    public StoreFinalAction()
+    public StoreFinal()
     {
         super( "Store a final value" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreAnyAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreInitial.java
similarity index 68%
copy from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreAnyAction.java
copy to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreInitial.java
index 57664a1..85f1e6d 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreAnyAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreInitial.java
@@ -6,23 +6,23 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
+import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
-import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
@@ -33,25 +33,28 @@
 
 
 /**
- * The action used to store a any value into a substring filter
- * 
+ * 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 StoreAnyAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class StoreInitial extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( StoreAnyAction.class );
-
-    /** Speedup for logs */
-    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
-
+    private static final Logger LOG = LoggerFactory.getLogger( StoreInitial.class );
 
     /**
      * Instantiates a new store any action.
      */
-    public StoreAnyAction()
+    public StoreInitial()
     {
-        super( "Store a any value" );
+        super( "Store an initial value" );
     }
 
 
@@ -60,30 +63,24 @@
      */
     public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
     {
-        SearchRequestDecorator decorator = container.getMessage();
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
 
         TLV tlv = container.getCurrentTLV();
 
         // Store the value.
-        SubstringFilter substringFilter = ( SubstringFilter ) decorator.getTerminalFilter();
+        SubstringFilter substringFilter = ( SubstringFilter ) searchRequestDecorator.getTerminalFilter();
 
         if ( tlv.getLength() == 0 )
         {
-            String msg = I18n.err( I18n.ERR_04019 );
+            String msg = I18n.err( I18n.ERR_04108 );
             LOG.error( msg );
             throw new DecoderException( msg );
         }
 
-        String any = Strings.utf8ToString(tlv.getValue().getData());
-        substringFilter.addAnySubstrings( any );
+        substringFilter.setInitialSubstrings( Strings.utf8ToString(tlv.getValue().getData()) );
 
         // 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 );
-        }
+        searchRequestDecorator.unstackFilters( container );
     }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreMatchValueAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreMatchValue.java
similarity index 83%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreMatchValueAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreMatchValue.java
index 6526aa6..58528cd 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreMatchValueAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreMatchValue.java
@@ -6,23 +6,23 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
+import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
-import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
 import org.apache.directory.shared.ldap.codec.search.ExtensibleMatchFilter;
@@ -33,13 +33,22 @@
 
 /**
  * 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 StoreMatchValueAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class StoreMatchValue extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( StoreMatchValueAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreMatchValue.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -48,7 +57,7 @@
     /**
      * Instantiates a new store match value action.
      */
-    public StoreMatchValueAction()
+    public StoreMatchValue()
     {
         super( "Store match Value" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreMatchingRuleDnAttributes.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreMatchingRuleDnAttributes.java
new file mode 100644
index 0000000..a04fab6
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.searchRequest.filter;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoder;
+import org.apache.directory.shared.asn1.ber.tlv.BooleanDecoderException;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.asn1.ber.tlv.Value;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.codec.search.ExtensibleMatchFilter;
+import org.apache.directory.shared.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.
+        Value 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() );
+        }
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Dn Attributes : {}", Boolean.valueOf( extensibleMatchFilter.isDnAttributes() ) );
+        }
+
+        // unstack the filters if needed
+        searchRequest.unstackFilters( container );
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreFinalAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreSubstringFilterType.java
similarity index 64%
copy from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreFinalAction.java
copy to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreSubstringFilterType.java
index 4a9c1b0..57251e9 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreFinalAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchRequest/filter/StoreSubstringFilterType.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchRequest.filter;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -27,32 +27,36 @@
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
 import org.apache.directory.shared.ldap.codec.search.SubstringFilter;
-
 import org.apache.directory.shared.util.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 
 /**
- * The action used to store a final value into a substring filter
- * 
+ * 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 StoreFinalAction extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
+public class StoreSubstringFilterType extends GrammarAction<LdapMessageContainer<SearchRequestDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( StoreFinalAction.class );
-
-    /** Speedup for logs */
-    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
-
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSubstringFilterType.class );
 
     /**
-     * Instantiates a new store final action.
+     * Instantiates a new action.
      */
-    public StoreFinalAction()
+    public StoreSubstringFilterType()
     {
-        super( "Store a final value" );
+        super( "Store Substring filter type" );
     }
 
 
@@ -61,30 +65,27 @@
      */
     public void action( LdapMessageContainer<SearchRequestDecorator> container ) throws DecoderException
     {
-        SearchRequestDecorator searchRequest = container.getMessage();
+        SearchRequestDecorator searchRequestDecorator = container.getMessage();
 
         TLV tlv = container.getCurrentTLV();
 
         // Store the value.
-        SubstringFilter substringFilter = ( SubstringFilter ) searchRequest.getTerminalFilter();
+        SubstringFilter substringFilter = ( SubstringFilter ) searchRequestDecorator.getTerminalFilter();
 
         if ( tlv.getLength() == 0 )
         {
-            String msg = I18n.err( I18n.ERR_04020 );
+            String msg = I18n.err( I18n.ERR_04106 );
             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 )
+        else
         {
-            LOG.debug( "Stored a any substring : {}", finalValue );
+            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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultDone/InitSearchResultDone.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultDone/InitSearchResultDone.java
new file mode 100644
index 0000000..8321efe
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultDone/InitSearchResultDone.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.shared.ldap.codec.actions.searchResultDone;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchResultDoneDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/AddAttributeType.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/AddAttributeType.java
new file mode 100644
index 0000000..84707a0
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/AddAttributeType.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.shared.ldap.codec.actions.searchResultEntry;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapException;
+import org.apache.directory.shared.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();
+
+        String type = "";
+
+        // 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
+        {
+            type = Strings.utf8ToString( tlv.getValue().getData() );
+
+            try
+            {
+                searchResultEntry.addAttribute( type );
+            }
+            catch ( LdapException ine )
+            {
+                // 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 )
+        {
+            LOG.debug( "Attribute type : {}", type );
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/InitSearchResultEntry.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/InitSearchResultEntry.java
new file mode 100644
index 0000000..0e48096
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/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.shared.ldap.codec.actions.searchResultEntry;
+
+
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/SearchResultAttributeValueAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/StoreSearchResultAttributeValue.java
similarity index 85%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/SearchResultAttributeValueAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/StoreSearchResultAttributeValue.java
index 79333a7..74c328f 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/SearchResultAttributeValueAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/StoreSearchResultAttributeValue.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchResultEntry;
 
 
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
@@ -31,13 +31,19 @@
 
 /**
  * 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 SearchResultAttributeValueAction extends GrammarAction<LdapMessageContainer<SearchResultEntryDecorator>>
+public class StoreSearchResultAttributeValue extends GrammarAction<LdapMessageContainer<SearchResultEntryDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( SearchResultAttributeValueAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreSearchResultAttributeValue.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -46,7 +52,7 @@
     /**
      * Instantiates a new search result attribute value action.
      */
-    public SearchResultAttributeValueAction()
+    public StoreSearchResultAttributeValue()
     {
         super( "Stores AttributeValue" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/StoreSearchResultEntryObjectName.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/StoreSearchResultEntryObjectName.java
new file mode 100644
index 0000000..b5cf116
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultEntry/StoreSearchResultEntryObjectName.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.shared.ldap.codec.actions.searchResultEntry;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultReference/InitSearchResultReference.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultReference/InitSearchResultReference.java
new file mode 100644
index 0000000..0a87997
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultReference/InitSearchResultReference.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.shared.ldap.codec.actions.searchResultReference;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.SearchResultReferenceDecorator;
+import org.apache.directory.shared.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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreReferenceAction.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultReference/StoreReference.java
similarity index 89%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreReferenceAction.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultReference/StoreReference.java
index b9ebd42..183ecf9 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/StoreReferenceAction.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/searchResultReference/StoreReference.java
@@ -6,18 +6,18 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
-package org.apache.directory.shared.ldap.codec.actions;
+package org.apache.directory.shared.ldap.codec.actions.searchResultReference;
 
 
 import org.apache.directory.shared.asn1.DecoderException;
@@ -38,13 +38,16 @@
 
 /**
  * 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 StoreReferenceAction extends GrammarAction<LdapMessageContainer<SearchResultReferenceDecorator>>
+public class StoreReference extends GrammarAction<LdapMessageContainer<SearchResultReferenceDecorator>>
 {
     /** The logger */
-    private static final Logger LOG = LoggerFactory.getLogger( StoreReferenceAction.class );
+    private static final Logger LOG = LoggerFactory.getLogger( StoreReference.class );
 
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG.isDebugEnabled();
@@ -53,7 +56,7 @@
     /**
      * Instantiates a new store reference action.
      */
-    public StoreReferenceAction()
+    public StoreReference()
     {
         super( "Store a reference" );
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/unbindRequest/InitUnbindRequest.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/unbindRequest/InitUnbindRequest.java
new file mode 100644
index 0000000..527b9a3
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/actions/unbindRequest/InitUnbindRequest.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.shared.ldap.codec.actions.unbindRequest;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.shared.asn1.ber.tlv.TLV;
+import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.decorators.UnbindRequestDecorator;
+import org.apache.directory.shared.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
+        UnbindRequestDecorator unbindRequest = new UnbindRequestDecorator(
+            container.getLdapCodecService(), new UnbindRequestImpl( container.getMessageId() ) );
+        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/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/ControlDecoder.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ControlDecoder.java
similarity index 96%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/ControlDecoder.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ControlDecoder.java
index 7d52568..c7ac564 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/ControlDecoder.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ControlDecoder.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.controls;
+package org.apache.directory.shared.ldap.codec.api;
 
 
 import org.apache.directory.shared.asn1.Asn1Object;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/ControlDecorator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ControlDecorator.java
similarity index 96%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/ControlDecorator.java
rename to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ControlDecorator.java
index 4d4b2b5..7cec340 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/ControlDecorator.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ControlDecorator.java
@@ -17,12 +17,10 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.codec.controls;
+package org.apache.directory.shared.ldap.codec.api;
 
 
 import org.apache.directory.shared.asn1.AbstractAsn1Object;
-import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.model.message.Control;
 
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/DefaultLdapCodecService.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/DefaultLdapCodecService.java
deleted file mode 100644
index f08e449..0000000
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/DefaultLdapCodecService.java
+++ /dev/null
@@ -1,298 +0,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.
- *
- */
-package org.apache.directory.shared.ldap.codec.api;
-
-
-import java.nio.ByteBuffer;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.apache.directory.shared.asn1.DecoderException;
-import org.apache.directory.shared.asn1.EncoderException;
-import org.apache.directory.shared.asn1.ber.Asn1Container;
-import org.apache.directory.shared.ldap.codec.BasicControlDecorator;
-import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
-import org.apache.directory.shared.ldap.codec.controls.cascade.CascadeFactory;
-import org.apache.directory.shared.ldap.codec.controls.manageDsaIT.ManageDsaITFactory;
-import org.apache.directory.shared.ldap.codec.controls.search.entryChange.EntryChangeFactory;
-import org.apache.directory.shared.ldap.codec.controls.search.pagedSearch.PagedResultsFactory;
-import org.apache.directory.shared.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory;
-import org.apache.directory.shared.ldap.codec.controls.search.subentries.SubentriesFactory;
-import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
-import org.apache.directory.shared.ldap.codec.protocol.mina.LdapProtocolCodecFactory;
-import org.apache.directory.shared.ldap.extras.controls.PasswordPolicyImpl;
-import org.apache.directory.shared.ldap.extras.controls.SyncDoneValue;
-import org.apache.directory.shared.ldap.extras.controls.SyncInfoValue;
-import org.apache.directory.shared.ldap.extras.controls.SyncModifyDn;
-import org.apache.directory.shared.ldap.extras.controls.SyncRequestValue;
-import org.apache.directory.shared.ldap.extras.controls.SyncStateValue;
-import org.apache.directory.shared.ldap.extras.controls.ppolicy_impl.PasswordPolicyFactory;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncDoneValueFactory;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncInfoValueFactory;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncModifyDnFactory;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncRequestValueFactory;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncStateValueFactory;
-import org.apache.directory.shared.ldap.model.message.Control;
-import org.apache.directory.shared.ldap.model.message.Message;
-import org.apache.directory.shared.ldap.model.message.controls.Cascade;
-import org.apache.directory.shared.ldap.model.message.controls.EntryChange;
-import org.apache.directory.shared.ldap.model.message.controls.ManageDsaIT;
-import org.apache.directory.shared.ldap.model.message.controls.OpaqueControl;
-import org.apache.directory.shared.ldap.model.message.controls.PagedResults;
-import org.apache.directory.shared.ldap.model.message.controls.PersistentSearch;
-import org.apache.directory.shared.ldap.model.message.controls.Subentries;
-import org.apache.directory.shared.util.exception.NotImplementedException;
-import org.apache.mina.filter.codec.ProtocolCodecFactory;
-
-
-/**
- * The default {@link LdapCodecService} implementation.
- *
- * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
- * @version $Rev$, $Date$
- */
-public class DefaultLdapCodecService implements LdapCodecService
-{
-    Map<String,ControlFactory<?,?>> controlFactories = new HashMap<String, ControlFactory<?,?>>();
-    Map<String,ExtendedOpFactory<?,?>> extReqFactories = new HashMap<String, ExtendedOpFactory<?,?>>();
-    Map<String,ExtendedOpFactory<?,?>> extResFactories = new HashMap<String, ExtendedOpFactory<?,?>>();
-    
-    
-    public DefaultLdapCodecService()
-    {
-        loadStockControls();
-    }
-    
-    
-    /**
-     * Loads the Controls implement out of the box in the codec.
-     */
-    private void loadStockControls()
-    {
-        CascadeFactory cascadeFactory = new CascadeFactory( this );
-        controlFactories.put( Cascade.OID, cascadeFactory );
-        
-        EntryChangeFactory entryChangeFactory = new EntryChangeFactory( this );
-        controlFactories.put( EntryChange.OID, entryChangeFactory );
-        
-        ManageDsaITFactory manageDsaITFactory = new ManageDsaITFactory( this );
-        controlFactories.put( ManageDsaIT.OID, manageDsaITFactory );
-        
-        PagedResultsFactory pagedResultsFactory = new PagedResultsFactory( this );
-        controlFactories.put( PagedResults.OID, pagedResultsFactory );
-        
-        PersistentSearchFactory persistentSearchFactory = new PersistentSearchFactory( this );
-        controlFactories.put( PersistentSearch.OID, persistentSearchFactory );
-
-        SubentriesFactory subentriesFactory = new SubentriesFactory( this );
-        controlFactories.put( Subentries.OID, subentriesFactory );
-        
-        // @TODO - these will eventually be removed to enable plugin driven
-        // registration instead
-        
-        SyncDoneValueFactory syncDoneValueFactory = new SyncDoneValueFactory( this );
-        controlFactories.put( SyncDoneValue.OID, syncDoneValueFactory );
-        
-        SyncInfoValueFactory syncInfoValueFactory = new SyncInfoValueFactory( this );
-        controlFactories.put( SyncInfoValue.OID, syncInfoValueFactory );
-        
-        SyncModifyDnFactory syncModifyDnFactory = new SyncModifyDnFactory( this );
-        controlFactories.put( SyncModifyDn.OID, syncModifyDnFactory );
-        
-        SyncRequestValueFactory syncRequestValueFactory = new SyncRequestValueFactory( this );
-        controlFactories.put( SyncRequestValue.OID, syncRequestValueFactory );
-
-        SyncStateValueFactory syncStateValueFactory = new SyncStateValueFactory( this );
-        controlFactories.put( SyncStateValue.OID, syncStateValueFactory );
-        
-        PasswordPolicyFactory passwordPolicyFactory = new PasswordPolicyFactory( this );
-        controlFactories.put( PasswordPolicyImpl.OID, passwordPolicyFactory );
-}
-    
-
-    //-------------------------------------------------------------------------
-    // ILdapCodecService implementation methods
-    //-------------------------------------------------------------------------
-    
-    
-    /**
-     * {@inheritDoc}
-     */
-    public void registerControl( ControlFactory<?,?> factory )
-    {
-        controlFactories.put( factory.getOid(), factory );
-    }
-    
-
-    /**
-     * {@inheritDoc}
-     */
-    public Iterator<String> registeredControls()
-    {
-        return Collections.unmodifiableSet( controlFactories.keySet() ).iterator();
-    }
-    
-
-    /**
-     * {@inheritDoc}
-     */
-    public Iterator<String> registeredExtendedRequests()
-    {
-        return Collections.unmodifiableSet( extReqFactories.keySet() ).iterator();
-    }
-
-    
-    /**
-     * {@inheritDoc}
-     */
-    public Iterator<String> registeredExtendedResponses()
-    {
-        return Collections.unmodifiableSet( extResFactories.keySet() ).iterator();
-    }
-
-    
-    /**
-     * {@inheritDoc}
-     */
-    public void registerExtendedOp( ExtendedOpFactory<?, ?> factory )
-    {
-        extReqFactories.put( factory.getRequestOid(), factory );
-    }
-
-    
-    /**
-     * {@inheritDoc}
-     * 
-     * @TODO - finish this up and add factory registration capabilities,
-     * of course there is one default mechanism for now.
-     */
-    public ProtocolCodecFactory newProtocolCodecFactory( boolean client )
-    {
-        if ( client )
-        {
-            return new LdapProtocolCodecFactory();
-        }
-        else
-        {
-            throw new NotImplementedException( 
-                "Filters may be different here, and we're probably going to " +
-                "want to have a protocol codec factory registration mechanism" +
-                "since this way we can swap in and out MINA/Grizzly" );
-        }
-    }
-
-    
-    /**
-     * {@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 (org.apache.directory.shared.ldap.codec.api.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();
-        javax.naming.ldap.BasicControl jndiControl = 
-            new javax.naming.ldap.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 );
-    }
-}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedOpFactory.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedRequestFactory.java
similarity index 60%
copy from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedOpFactory.java
copy to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedRequestFactory.java
index 6295ba6..f90c87d 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedOpFactory.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedRequestFactory.java
@@ -20,23 +20,40 @@
 package org.apache.directory.shared.ldap.codec.api;
 
 
+import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
 import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
 
 
 /**
- * The LdapCodec interface, defined by the codec API.
+ * The factor interface, defined by the codec API for creating new 
+ * ExtendedRequests.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$, $Date$
  */
-public interface ExtendedOpFactory<Q extends ExtendedRequest, P extends ExtendedResponse>
+public interface ExtendedRequestFactory<Q extends ExtendedRequest,P extends ExtendedResponse>
 {
-    String getResponseOid();
+    /**
+     * Gets the OID of the extended requests this factory generates.
+     *
+     * @return the extended request OID
+     */
+    String getOid();
     
-    String getRequestOid();
     
+    /**
+     *  @return A new instance of the ExtendedRequest.
+     */
     Q newRequest();
     
-    P newResponse();
+    
+    /**
+     * 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.
+     */
+    P newResponse( byte[] encodedValue ) throws DecoderException;
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/LdapCodecService.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/LdapCodecService.java
index b758a0a..1b14fc6 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/LdapCodecService.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/LdapCodecService.java
@@ -26,6 +26,7 @@
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
 import org.apache.mina.filter.codec.ProtocolCodecFactory;
 
 
@@ -37,6 +38,12 @@
  */
 public interface LdapCodecService
 {
+    
+    // ------------------------------------------------------------------------
+    // Control Methods
+    // ------------------------------------------------------------------------
+
+    
     /**
      * Returns an Iterator over the OID Strings of registered controls.
      * 
@@ -46,21 +53,11 @@
     
     
     /**
-     * Returns an Iterator over the OID Strings of registered extended 
-     * requests.
-     *
-     * @return The registered extended request OID Strings
+     * Checks if a control has been registered.
+     * 
+     * @return The OID of the control to check for registration
      */
-    Iterator<String> registeredExtendedRequests();
-    
-    
-    /**
-     * Returns an Iterator over the OID Strings of registered extended 
-     * responses.
-     *
-     * @return The registered extended response OID Strings
-     */
-    Iterator<String> registeredExtendedResponses();
+    boolean isControlRegistered( String oid );
     
     
     /**
@@ -68,16 +65,15 @@
      * 
      * @param factory The control factory
      */
-    void registerControl( ControlFactory<?,?> factory );
+    ControlFactory<?,?> registerControl( ControlFactory<?,?> factory );
     
     
     /**
-     * Registers an {@link ExtendedOpFactory} for generating extended request 
-     * response pairs.
+     * Unregisters an {@link ControlFactory} with this service.
      * 
-     * @param factory The extended operation factory
+     * @param oid The oid of the control the factory is associated with.
      */
-    void registerExtendedOp( ExtendedOpFactory<?,?> factory );
+    ControlFactory<?,?> unregisterControl( String oid );
     
     
     /**
@@ -99,16 +95,6 @@
     
     
     /**
-     * Creates a new LDAP {@link ProtocolCodecFactory}.
-     *
-     * @param client if true a factory designed for clients is returned, 
-     * otherwise one for servers is returned.
-     * @return the client or server specific {@link ProtocolCodecFactory}
-     */
-    ProtocolCodecFactory newProtocolCodecFactory( boolean client );
-    
-    
-    /**
      * Creates a JNDI control from the ldap model's control.
      *
      * @param modelControl The model's control.
@@ -127,6 +113,115 @@
      */
     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 ExtendedRequestFactory} for generating extended request 
+     * response pairs.
+     * 
+     * @param factory The extended request factory
+     * @return The displaced factory if one existed for the oid
+     */
+    ExtendedRequestFactory<?,?> registerExtendedRequest( ExtendedRequestFactory<?,?> factory );
+    
+    
+    /**
+     * Unregisters an {@link ExtendedRequestFactory} for generating extended 
+     * request response pairs.
+     * 
+     * @param oid The extended request oid
+     * @return The displaced factory if one existed for the oid
+     */
+    ExtendedRequestFactory<?,?> unregisterExtendedRequest( String oid );
+    
+    
+    // ------------------------------------------------------------------------
+    // Extended Response Methods
+    // ------------------------------------------------------------------------
+
+    
+    /**
+     * Returns an Iterator over the OID Strings of registered unsolicited 
+     * extended responses.
+     *
+     * @return The registered unsolicited extended response OID Strings
+     */
+    Iterator<String> registeredUnsolicitedResponses();
+    
+    
+    /**
+     * Registers an {@link UnsolicitedResponseFactory} for generating extended
+     * responses sent by servers without an extended request.
+     * 
+     * @param factory The unsolicited response creating factory
+     * @return The displaced factory if one existed for the oid
+     */
+    UnsolicitedResponseFactory<?> registerUnsolicitedResponse( UnsolicitedResponseFactory<?> factory );
+
+    
+    /**
+     * Unregisters an {@link UnsolicitedResponseFactory} for generating 
+     * extended responses sent by servers without an extended request.
+     * 
+     * @param oid The unsolicited response oid
+     */
+    UnsolicitedResponseFactory<?> unregisterUnsolicitedResponse( String oid );
+
+    
+    /**
+     * 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;
+    
+    
+    // ------------------------------------------------------------------------
+    // Extended Request/Response Methods
+    // ------------------------------------------------------------------------
+
+    
+    /**
+     * Creates a new LDAP {@link ProtocolCodecFactory}.
+     *
+     * @param client if true a factory designed for clients is returned, 
+     * otherwise one for servers is returned.
+     * @return the client or server specific {@link ProtocolCodecFactory}
+     */
+    ProtocolCodecFactory newProtocolCodecFactory( boolean client );
+
+    
+    /**
+     * Creates a new MessageContainer.
+     *
+     * @TODO akarasulu - Wondering why is this not an LdapMessageContainer?
+     * @return The newly created LDAP MessageContainer instance.
+     */
     Asn1Container newMessageContainer();
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/LdapCodecServiceFactory.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/LdapCodecServiceFactory.java
new file mode 100644
index 0000000..48b2e56
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/LdapCodecServiceFactory.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.shared.ldap.codec.api;
+
+
+import org.apache.directory.shared.ldap.codec.osgi.DefaultLdapCodecService;
+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 class LdapCodecServiceFactory
+{
+    /** Logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( LdapCodecServiceFactory.class );
+    
+    /** The LdapCodecService singleton bound to this factory */
+    private static LdapCodecService ldapCodecService;
+    
+    /** Whether or not the standalone implementation is being used */
+    private static boolean usingStandaloneImplementation;
+    
+    
+    /**
+     * 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 LdapCodecService 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( LdapCodecService ldapCodecService )
+    {
+        /*
+         * If the class member is already set we have problems.
+         */
+        
+        if ( LdapCodecServiceFactory.ldapCodecService != null )
+        {
+            StringBuilder sb = new StringBuilder( "The LdapCodecService is already set to an instance of " );
+            sb.append( LdapCodecServiceFactory.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 LdapCodecService> serviceClass = ( Class<? extends LdapCodecService> ) 
+                    Class.forName( "org.apache.directory.shared.ldap.codec.standalone.StandaloneLdapCodecService" );
+                LdapCodecServiceFactory.ldapCodecService = serviceClass.newInstance();
+                usingStandaloneImplementation = true;
+            }
+            catch ( Exception e )
+            {
+                LOG.error( "Failed to instantiate a viable instance, instantiating new instance of ", e );
+            }
+        }
+        else
+        {
+            usingStandaloneImplementation = false;
+            LdapCodecServiceFactory.ldapCodecService = ldapCodecService;
+        }
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedOpFactory.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/UnsolicitedResponseFactory.java
similarity index 66%
copy from ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedOpFactory.java
copy to ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/UnsolicitedResponseFactory.java
index 6295ba6..335e171 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/ExtendedOpFactory.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/api/UnsolicitedResponseFactory.java
@@ -20,23 +20,29 @@
 package org.apache.directory.shared.ldap.codec.api;
 
 
-import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
+import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
 
 
 /**
- * The LdapCodec interface, defined by the codec API.
+ * A factory which generates unsolicited server ExtendedResponses without 
+ * requiring an initiating client ExtendedRequest.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$, $Date$
  */
-public interface ExtendedOpFactory<Q extends ExtendedRequest, P extends ExtendedResponse>
+public interface UnsolicitedResponseFactory<R extends ExtendedResponse>
 {
-    String getResponseOid();
+    /**
+     * Gets the OID of the {@link ExtendedResponse} this factory generates.
+     *
+     * @return the extended response OID
+     */
+    String getOid();
     
-    String getRequestOid();
     
-    Q newRequest();
-    
-    P newResponse();
+    /**
+     *  @return A new instance of the ExtendedResponse.
+     */
+    R newResponse( byte[] encodedValue ) throws DecoderException;
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/cascade/CascadeDecorator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/cascade/CascadeDecorator.java
index f39c285..626b0bd 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/cascade/CascadeDecorator.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/cascade/CascadeDecorator.java
@@ -27,7 +27,7 @@
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.model.message.controls.Cascade;
 
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/manageDsaIT/ManageDsaITDecorator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/manageDsaIT/ManageDsaITDecorator.java
index 887b43c..df46579 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/manageDsaIT/ManageDsaITDecorator.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/manageDsaIT/ManageDsaITDecorator.java
@@ -25,8 +25,8 @@
 import org.apache.directory.shared.asn1.Asn1Object;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
 import org.apache.directory.shared.ldap.model.message.controls.ManageDsaIT;
 
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeDecorator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeDecorator.java
index ce0f7e1..0cf625f 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeDecorator.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeDecorator.java
@@ -30,8 +30,8 @@
 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
 import org.apache.directory.shared.ldap.model.message.controls.ChangeType;
 import org.apache.directory.shared.ldap.model.message.controls.EntryChange;
 import org.apache.directory.shared.ldap.model.message.controls.EntryChangeImpl;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeGrammar.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeGrammar.java
index 88c2d1c..6e5e5e0 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeGrammar.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeGrammar.java
@@ -46,7 +46,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class EntryChangeGrammar extends AbstractGrammar
+public final class EntryChangeGrammar extends AbstractGrammar<EntryChangeContainer>
 {
     /** The logger */
     static final Logger LOG = LoggerFactory.getLogger( EntryChangeGrammar.class );
@@ -55,12 +55,13 @@
     static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
     /** The instance of grammar. EntryChangeGrammar is a singleton */
-    private static Grammar instance = new EntryChangeGrammar();
+    private static Grammar<?> instance = new EntryChangeGrammar();
 
 
     /**
      * Creates a new EntryChangeGrammar object.
      */
+    @SuppressWarnings("unchecked")
     private EntryChangeGrammar()
     {
         setName( EntryChangeGrammar.class.getName() );
@@ -76,7 +77,7 @@
         //
         // Initialization of the structure
         super.transitions[ EntryChangeStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
-            new GrammarTransition( EntryChangeStates.START_STATE,
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.START_STATE,
                                     EntryChangeStates.EC_SEQUENCE_STATE,
                                     UniversalTag.SEQUENCE.getValue(), null );
 
@@ -89,7 +90,7 @@
         //
         // Evaluates the changeType
         super.transitions[ EntryChangeStates.EC_SEQUENCE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] =
-            new GrammarTransition( EntryChangeStates.EC_SEQUENCE_STATE,
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.EC_SEQUENCE_STATE,
                                     EntryChangeStates.CHANGE_TYPE_STATE,
                                     UniversalTag.ENUMERATED.getValue(),
             new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl changeType" )
@@ -151,7 +152,7 @@
         // 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( EntryChangeStates.CHANGE_TYPE_STATE,
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE,
                                     EntryChangeStates.PREVIOUS_DN_STATE,
                                     UniversalTag.OCTET_STRING.getValue(),
             new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl previousDN" )
@@ -234,7 +235,7 @@
         //
         // Set the changeNumber into the structure
         super.transitions[ EntryChangeStates.PREVIOUS_DN_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
-            new GrammarTransition( EntryChangeStates.PREVIOUS_DN_STATE,
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.PREVIOUS_DN_STATE,
                                     EntryChangeStates.CHANGE_NUMBER_STATE,
                                     UniversalTag.INTEGER.getValue(),
                 setChangeNumberAction );
@@ -249,7 +250,7 @@
         //
         // Set the changeNumber into the structure
         super.transitions[ EntryChangeStates.CHANGE_TYPE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
-            new GrammarTransition( EntryChangeStates.CHANGE_TYPE_STATE,
+            new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE,
                                     EntryChangeStates.CHANGE_NUMBER_STATE,
                                     UniversalTag.INTEGER.getValue(),
                 setChangeNumberAction );
@@ -261,7 +262,7 @@
      * 
      * @return An instance on this grammar
      */
-    public static Grammar getInstance()
+    public static Grammar<?> getInstance()
     {
         return instance;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeStates.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeStates.java
index a002c63..5f68979 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeStates.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/entryChange/EntryChangeStates.java
@@ -78,7 +78,7 @@
      * @param grammar The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<?> grammar )
     {
         if ( grammar instanceof EntryChangeGrammar )
         {
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsDecorator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsDecorator.java
index 6c2186d..026ce9e 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsDecorator.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsDecorator.java
@@ -32,7 +32,7 @@
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.model.message.controls.PagedResults;
 import org.apache.directory.shared.ldap.model.message.controls.PagedResultsImpl;
 import org.apache.directory.shared.util.Strings;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsGrammar.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsGrammar.java
index ec36574..c77be96 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsGrammar.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsGrammar.java
@@ -48,7 +48,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class PagedResultsGrammar extends AbstractGrammar
+public final class PagedResultsGrammar extends AbstractGrammar<PagedResultsContainer>
 {
     /** The logger */
     static final Logger LOG = LoggerFactory.getLogger( PagedResultsGrammar.class );
@@ -57,12 +57,13 @@
     static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
     /** The instance of grammar. PagedSearchControlGrammar is a singleton */
-    private static Grammar instance = new PagedResultsGrammar();
+    private static Grammar<?> instance = new PagedResultsGrammar();
 
 
     /**
      * Creates a new PagedSearchControlGrammar object.
      */
+    @SuppressWarnings("unchecked")
     private PagedResultsGrammar()
     {
         setName( PagedResultsGrammar.class.getName() );
@@ -78,7 +79,7 @@
          * Nothing to do
          */
         super.transitions[ PagedResultsStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
-            new GrammarTransition( PagedResultsStates.START_STATE,
+            new GrammarTransition<PagedResultsContainer>( PagedResultsStates.START_STATE,
                                     PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE,
                                     UniversalTag.SEQUENCE.getValue(), null );
 
@@ -93,7 +94,7 @@
          * Stores the size value
          */
         super.transitions[ PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
-            new GrammarTransition( PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE,
+            new GrammarTransition<PagedResultsContainer>( PagedResultsStates.PAGED_SEARCH_SEQUENCE_STATE,
                 PagedResultsStates.SIZE_STATE,
                 UniversalTag.INTEGER.getValue(),
                 new GrammarAction<PagedResultsContainer>( "Set PagedSearchControl size" )
@@ -140,7 +141,7 @@
          * Stores the cookie flag
          */
         super.transitions[ PagedResultsStates.SIZE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
-            new GrammarTransition( PagedResultsStates.SIZE_STATE,
+            new GrammarTransition<PagedResultsContainer>( PagedResultsStates.SIZE_STATE,
                                     PagedResultsStates.COOKIE_STATE, UniversalTag.OCTET_STRING.getValue(),
                 new GrammarAction<PagedResultsContainer>( "Set PagedSearchControl cookie" )
             {
@@ -169,7 +170,7 @@
      * 
      * @return An instance on this grammar
      */
-    public static Grammar getInstance()
+    public static Grammar<?> getInstance()
     {
         return instance;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsStates.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsStates.java
index 2873331..11be1e8 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsStates.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/pagedSearch/PagedResultsStates.java
@@ -75,7 +75,7 @@
      * @param grammar The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<?> grammar )
     {
         if ( grammar instanceof PagedResultsGrammar )
         {
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchDecorator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchDecorator.java
index fb2e6e5..bc33218 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchDecorator.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchDecorator.java
@@ -31,7 +31,7 @@
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.model.message.controls.ChangeType;
 import org.apache.directory.shared.ldap.model.message.controls.PersistentSearch;
 import org.apache.directory.shared.ldap.model.message.controls.PersistentSearchImpl;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchGrammar.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchGrammar.java
index 82c78fa..da09c52 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchGrammar.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchGrammar.java
@@ -57,7 +57,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class PersistentSearchGrammar extends AbstractGrammar
+public final class PersistentSearchGrammar extends AbstractGrammar<PersistentSearchContainer>
 {
     /** The logger */
     static final Logger LOG = LoggerFactory.getLogger( PersistentSearchGrammar.class );
@@ -66,12 +66,13 @@
     static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
     /** The instance of grammar. PSearchControlGrammar is a singleton */
-    private static Grammar instance = new PersistentSearchGrammar();
+    private static Grammar<?> instance = new PersistentSearchGrammar();
 
 
     /**
      * Creates a new PSearchControlGrammar object.
      */
+    @SuppressWarnings("unchecked")
     private PersistentSearchGrammar()
     {
         setName( PersistentSearchGrammar.class.getName() );
@@ -87,7 +88,7 @@
          * Initialize the persistence search object
          */
         super.transitions[ PersistentSearchStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
-            new GrammarTransition( PersistentSearchStates.START_STATE,
+            new GrammarTransition<PersistentSearchContainer>( PersistentSearchStates.START_STATE,
                                     PersistentSearchStates.PSEARCH_SEQUENCE_STATE,
                                     UniversalTag.SEQUENCE.getValue(), null );
 
@@ -101,7 +102,7 @@
          * Stores the change types value
          */
         super.transitions[ PersistentSearchStates.PSEARCH_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] =
-            new GrammarTransition( PersistentSearchStates.PSEARCH_SEQUENCE_STATE,
+            new GrammarTransition<PersistentSearchContainer>( PersistentSearchStates.PSEARCH_SEQUENCE_STATE,
                 PersistentSearchStates.CHANGE_TYPES_STATE,
                 UniversalTag.INTEGER.getValue(),
                 new GrammarAction<PersistentSearchContainer>( "Set PSearchControl changeTypes" )
@@ -143,7 +144,7 @@
          * Stores the change only flag
          */
         super.transitions[ PersistentSearchStates.CHANGE_TYPES_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
-            new GrammarTransition( PersistentSearchStates.CHANGE_TYPES_STATE,
+            new GrammarTransition<PersistentSearchContainer>( PersistentSearchStates.CHANGE_TYPES_STATE,
                                     PersistentSearchStates.CHANGES_ONLY_STATE, UniversalTag.BOOLEAN.getValue(),
                 new GrammarAction<PersistentSearchContainer>( "Set PSearchControl changesOnly" )
             {
@@ -181,7 +182,7 @@
          * Stores the return ECs flag 
          */
         super.transitions[ PersistentSearchStates.CHANGES_ONLY_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
-            new GrammarTransition( PersistentSearchStates.CHANGES_ONLY_STATE,
+            new GrammarTransition<PersistentSearchContainer>( PersistentSearchStates.CHANGES_ONLY_STATE,
                                     PersistentSearchStates.RETURN_ECS_STATE, UniversalTag.BOOLEAN.getValue(),
                 new GrammarAction<PersistentSearchContainer>( "Set PSearchControl returnECs" )
             {
@@ -219,7 +220,7 @@
      * 
      * @return An instance on this grammar
      */
-    public static Grammar getInstance()
+    public static Grammar<?> getInstance()
     {
         return instance;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchStates.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchStates.java
index fde564e..4f7e83f 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchStates.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/persistentSearch/PersistentSearchStates.java
@@ -77,7 +77,7 @@
      * @param grammar The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<?> grammar )
     {
         if ( grammar instanceof PersistentSearchGrammar )
         {
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesDecorator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesDecorator.java
index cf6272b..3b9734a 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesDecorator.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesDecorator.java
@@ -28,8 +28,8 @@
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
 import org.apache.directory.shared.ldap.model.message.controls.Subentries;
 import org.apache.directory.shared.ldap.model.message.controls.SubentriesImpl;
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesGrammar.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesGrammar.java
index b7f312b..d9ae19d 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesGrammar.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesGrammar.java
@@ -42,18 +42,19 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class SubentriesGrammar extends AbstractGrammar
+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 instance = new SubentriesGrammar();
+    private static Grammar<SubentriesContainer> instance = new SubentriesGrammar();
 
 
     /**
      * Creates a new SubEntryGrammar object.
      */
+    @SuppressWarnings("unchecked")
     private SubentriesGrammar()
     {
         setName( SubentriesGrammar.class.getName() );
@@ -62,7 +63,7 @@
         super.transitions = new GrammarTransition[ SubentriesStates.LAST_SUB_ENTRY_STATE.ordinal()][256];
 
         super.transitions[ SubentriesStates.START_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
-            new GrammarTransition( SubentriesStates.START_STATE,
+            new GrammarTransition<SubentriesContainer>( SubentriesStates.START_STATE,
                                     SubentriesStates.SUB_ENTRY_VISIBILITY_STATE, UniversalTag.BOOLEAN.getValue(),
                 new GrammarAction<SubentriesContainer>( "SubEntryControl visibility" )
             {
@@ -102,7 +103,7 @@
      * 
      * @return An instance on this grammar
      */
-    public static Grammar getInstance()
+    public static Grammar<SubentriesContainer> getInstance()
     {
         return instance;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesStates.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesStates.java
index 6df1010..4ac5094 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesStates.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/controls/search/subentries/SubentriesStates.java
@@ -70,7 +70,7 @@
      * @param grammar The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<SubentriesContainer> grammar )
     {
         if ( grammar instanceof SubentriesGrammar )
         {
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/decorators/MessageDecorator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/decorators/MessageDecorator.java
index f0e00a3..28a804e 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/decorators/MessageDecorator.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/decorators/MessageDecorator.java
@@ -24,9 +24,9 @@
 import java.util.Map;
 
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.codec.api.Decorator;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
 import org.apache.directory.shared.ldap.model.exception.MessageException;
 import org.apache.directory.shared.ldap.model.message.AbandonRequest;
 import org.apache.directory.shared.ldap.model.message.AddRequest;
@@ -302,7 +302,7 @@
         Control decorated;
         CodecControl<? extends Control> controlDecorator;
         
-        if ( control instanceof ControlDecorator )
+        if ( control instanceof ControlDecorator)
         {
             controlDecorator = (org.apache.directory.shared.ldap.codec.api.CodecControl<? extends Control> ) control;
             decorated = controlDecorator.getDecorated();
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/osgi/DefaultActivator.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/osgi/DefaultActivator.java
new file mode 100644
index 0000000..2ad9f3a
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/osgi/DefaultActivator.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.shared.ldap.codec.osgi;
+
+
+import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.api.LdapCodecServiceFactory;
+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>
+ */
+@SuppressWarnings({"UnusedDeclaration"})
+public class DefaultActivator implements BundleActivator
+{
+    private DefaultLdapCodecService codec;
+    private ServiceRegistration registration;
+
+
+    @SuppressWarnings({"UnusedDeclaration"})
+    public DefaultActivator()
+    {
+        this.codec = new DefaultLdapCodecService();
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void start( BundleContext bundleContext ) throws Exception
+    {
+        registration = bundleContext.registerService( LdapCodecService.class.getName(), codec, null );
+        LdapCodecServiceFactory.initialize( codec );
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop( BundleContext bundleContext ) throws Exception
+    {
+        registration.unregister();
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/osgi/DefaultLdapCodecService.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/osgi/DefaultLdapCodecService.java
new file mode 100644
index 0000000..5a57d92
--- /dev/null
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/osgi/DefaultLdapCodecService.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.shared.ldap.codec.osgi;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.asn1.EncoderException;
+import org.apache.directory.shared.asn1.ber.Asn1Container;
+import org.apache.directory.shared.ldap.codec.BasicControlDecorator;
+import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
+import org.apache.directory.shared.ldap.codec.api.CodecControl;
+import org.apache.directory.shared.ldap.codec.api.ControlFactory;
+import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
+import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.api.UnsolicitedResponseFactory;
+import org.apache.directory.shared.ldap.codec.controls.cascade.CascadeFactory;
+import org.apache.directory.shared.ldap.codec.controls.manageDsaIT.ManageDsaITFactory;
+import org.apache.directory.shared.ldap.codec.controls.search.entryChange.EntryChangeFactory;
+import org.apache.directory.shared.ldap.codec.controls.search.pagedSearch.PagedResultsFactory;
+import org.apache.directory.shared.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory;
+import org.apache.directory.shared.ldap.codec.controls.search.subentries.SubentriesFactory;
+import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.protocol.mina.LdapProtocolCodecFactory;
+import org.apache.directory.shared.ldap.model.message.Control;
+import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
+import org.apache.directory.shared.ldap.model.message.ExtendedResponseImpl;
+import org.apache.directory.shared.ldap.model.message.Message;
+import org.apache.directory.shared.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.shared.util.exception.NotImplementedException;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * The default {@link LdapCodecService} implementation.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$, $Date$
+ */
+public class DefaultLdapCodecService implements LdapCodecService
+{
+    /** A logger */
+    private static final Logger LOG = LoggerFactory.getLogger( DefaultLdapCodecService.class );
+
+    /** The map of registered {@link org.apache.directory.shared.ldap.codec.api.ControlFactory}'s */
+    private Map<String,ControlFactory<?,?>> controlFactories = new HashMap<String, ControlFactory<?,?>>();
+
+    /** The map of registered {@link org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory}'s by request OID */
+    private Map<String,ExtendedRequestFactory<?,?>> extReqFactories = new HashMap<String, ExtendedRequestFactory<?,?>>();
+
+    /** The map of registered {@link UnsolicitedResponseFactory}'s by request OID */
+    private Map<String,UnsolicitedResponseFactory<?>> unsolicitedFactories = new HashMap<String, UnsolicitedResponseFactory<?>>();
+
+
+    /**
+     * Creates a new instance of DefaultLdapCodecService.
+     */
+    DefaultLdapCodecService()
+    {
+        loadStockControls();
+    }
+
+
+    /**
+     * Loads the Controls implement out of the box in the codec.
+     */
+    private void loadStockControls()
+    {
+        ControlFactory<?, ?> factory = new CascadeFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+
+        factory = new EntryChangeFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+
+        factory = new ManageDsaITFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+
+        factory = new PagedResultsFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+
+        factory = new PersistentSearchFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.getOid() );
+
+        factory = new SubentriesFactory( this );
+        controlFactories.put( factory.getOid(), factory );
+        LOG.info( "Registered pre-bundled control factory: {}", factory.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( extReqFactories.keySet() ).iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedRequestFactory<?, ?> registerExtendedRequest( ExtendedRequestFactory<?,?> factory )
+    {
+        return extReqFactories.put( factory.getOid(), factory );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * @TODO - finish this up and add factory registration capabilities,
+     * of course there is one default mechanism for now.
+     */
+    public ProtocolCodecFactory newProtocolCodecFactory( boolean client )
+    {
+        if ( client )
+        {
+            return new LdapProtocolCodecFactory( this );
+        }
+        else
+        {
+            throw new NotImplementedException(
+                "Filters may be different here, and we're probably going to " +
+                "want to have a protocol codec factory registration mechanism" +
+                "since this way we can swap in and out MINA/Grizzly" );
+        }
+    }
+
+
+    /**
+     * {@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();
+        javax.naming.ldap.BasicControl jndiControl = 
+            new javax.naming.ldap.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 ExtendedRequestFactory<?, ?> unregisterExtendedRequest( String oid )
+    {
+        return extReqFactories.remove( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<String> registeredUnsolicitedResponses()
+    {
+        return Collections.unmodifiableSet( unsolicitedFactories.keySet() ).iterator();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnsolicitedResponseFactory<?> registerUnsolicitedResponse( UnsolicitedResponseFactory<?> factory )
+    {
+        return unsolicitedFactories.put( factory.getOid(), factory );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public UnsolicitedResponseFactory<?> unregisterUnsolicitedResponse( String oid )
+    {
+        return unsolicitedFactories.remove( oid );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public javax.naming.ldap.ExtendedResponse toJndi( final ExtendedResponse modelResponse ) throws EncoderException
+    {
+        final byte[] encodedValue = new byte[ modelResponse.getEncodedValue().length ];
+        System.arraycopy( modelResponse.getEncodedValue(), 0, encodedValue, 0, modelResponse.getEncodedValue().length );
+        
+        return new javax.naming.ldap.ExtendedResponse()
+        {
+            private static final long serialVersionUID = 2955142105375495493L;
+
+            public String getID()
+            {
+                return modelResponse.getID();
+            }
+
+            public byte[] getEncodedValue()
+            {
+                return encodedValue;
+            }
+        };
+    }
+    
+
+    /**
+     * {@inheritDoc}
+     */
+    public ExtendedResponse fromJndi( javax.naming.ldap.ExtendedResponse jndiResponse ) throws DecoderException
+    {   
+        ExtendedResponse modelResponse;
+        ExtendedRequestFactory<?,?> extendedRequestFactory = extReqFactories.get( jndiResponse.getID() );
+        UnsolicitedResponseFactory<?> unsolicitedResponseFactory = unsolicitedFactories.get( jndiResponse.getID() );
+        
+        if ( unsolicitedResponseFactory != null )
+        {
+            modelResponse = unsolicitedResponseFactory.newResponse( jndiResponse.getEncodedValue() );
+        }
+        else if ( extendedRequestFactory != null )
+        {
+            modelResponse = extendedRequestFactory.newResponse( jndiResponse.getEncodedValue() );
+        }
+        else
+        {
+            modelResponse = new ExtendedResponseImpl( jndiResponse.getID() );
+            modelResponse.setResponseValue( jndiResponse.getEncodedValue() );
+        }
+        
+        return modelResponse;
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/protocol/mina/LdapProtocolCodecFactory.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/protocol/mina/LdapProtocolCodecFactory.java
index 800997d..335fbef 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/protocol/mina/LdapProtocolCodecFactory.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/protocol/mina/LdapProtocolCodecFactory.java
@@ -20,6 +20,7 @@
 package org.apache.directory.shared.ldap.codec.protocol.mina;
 
 
+import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.mina.core.session.IoSession;
 import org.apache.mina.filter.codec.ProtocolCodecFactory;
 import org.apache.mina.filter.codec.ProtocolDecoder;
@@ -39,13 +40,19 @@
     /** The LdapEncoder key */
     public static final String LDAP_ENCODER = "LDAP_ENCODER";
 
+    
+    private LdapCodecService codec;
 
+    
     /**
      * Creates a new instance of LdapProtocolCodecFactory. It
      * creates the encoded an decoder instances.
+     * 
+     * @param codec The codec associated with this protocol codec factory
      */
-    public LdapProtocolCodecFactory()
+    public LdapProtocolCodecFactory( LdapCodecService codec )
     {
+        this.codec = codec;
     }
 
 
@@ -69,6 +76,6 @@
      */
     public ProtocolEncoder getEncoder( IoSession session )
     {
-        return new LdapProtocolEncoder();
+        return new LdapProtocolEncoder( codec );
     }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/protocol/mina/LdapProtocolEncoder.java b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/protocol/mina/LdapProtocolEncoder.java
index 76fb8a2..39d7336 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/protocol/mina/LdapProtocolEncoder.java
+++ b/ldap-codec/src/main/java/org/apache/directory/shared/ldap/codec/protocol/mina/LdapProtocolEncoder.java
@@ -23,6 +23,7 @@
 import java.nio.ByteBuffer;
 
 import org.apache.directory.shared.ldap.codec.LdapEncoder;
+import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.model.message.Message;
 import org.apache.mina.core.buffer.IoBuffer;
 import org.apache.mina.core.session.IoSession;
@@ -38,7 +39,18 @@
 public class LdapProtocolEncoder implements ProtocolEncoder
 {
     /** The stateful encoder */
-    private static final LdapEncoder ENCODER = new LdapEncoder();
+    private LdapEncoder encoder;
+    
+    
+    /**
+     * Creates a new instance of LdapProtocolEncoder.
+     *
+     * @param codec The LDAP codec service associated with this encoder.
+     */
+    public LdapProtocolEncoder( LdapCodecService codec )
+    {
+        this.encoder = new LdapEncoder( codec );
+    }
 
 
     /**
@@ -46,7 +58,7 @@
      */
     public void encode( IoSession session, Object message, ProtocolEncoderOutput out ) throws Exception
     {
-        ByteBuffer buffer = ENCODER.encodeMessage( ( Message ) message );
+        ByteBuffer buffer = encoder.encodeMessage( ( Message ) message );
 
         IoBuffer ioBuffer = IoBuffer.wrap( buffer );
 
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapControlTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapControlTest.java
index 7a97267..48c3403 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapControlTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapControlTest.java
@@ -35,10 +35,9 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.AbandonRequestDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.AbandonRequest;
 import org.apache.directory.shared.ldap.model.message.AbandonRequestImpl;
 import org.apache.directory.shared.ldap.model.message.Control;
@@ -50,13 +49,8 @@
 
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class LdapControlTest
+public class LdapControlTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a Request with controls
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapDecoderTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapDecoderTest.java
index e5436e0..fe10ce5 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapDecoderTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapDecoderTest.java
@@ -35,10 +35,9 @@
 import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.BindRequest;
 import org.apache.directory.shared.ldap.model.message.Message;
 import org.apache.directory.shared.util.Strings;
@@ -59,9 +58,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class LdapDecoderTest
+public class LdapDecoderTest extends AbstractCodecServiceTest
 {
-    LdapCodecService codec = new DefaultLdapCodecService();
     
     private static class LdapProtocolDecoderOutput extends AbstractProtocolDecoderOutput 
     {
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapMessageTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapMessageTest.java
index 28d3482..ff29074 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapMessageTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapMessageTest.java
@@ -32,10 +32,9 @@
 import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.EncoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.UnbindRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Message;
 import org.apache.directory.shared.ldap.model.message.UnbindRequest;
 import org.apache.directory.shared.ldap.model.message.UnbindRequestImpl;
@@ -51,17 +50,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class LdapMessageTest
+public class LdapMessageTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-    
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
-    // ~ Methods
-    // ------------------------------------------------------------------------------------
-
     /**
      * Test the decoding of null length messageId
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapResultTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapResultTest.java
index f8527cd..2134886 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapResultTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/LdapResultTest.java
@@ -30,14 +30,14 @@
 
 import com.mycila.junit.concurrent.Concurrency;
 import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.AddResponseDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.AddResponse;
 import org.apache.directory.shared.ldap.model.message.Message;
 import org.apache.directory.shared.ldap.model.message.Referral;
@@ -55,17 +55,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class LdapResultTest
+public class LdapResultTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-    
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
-    // ~ Methods
-    // ------------------------------------------------------------------------------------
-
     /**
      * Test the decoding of a AddResponse with no LdapResult
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/abandon/AbandonRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/abandon/AbandonRequestTest.java
index f88e727..231935b 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/abandon/AbandonRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/abandon/AbandonRequestTest.java
@@ -33,13 +33,11 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.AbandonRequestDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.AbandonRequest;
 import org.apache.directory.shared.ldap.model.message.AbandonRequestImpl;
 import org.apache.directory.shared.ldap.model.message.Control;
@@ -56,14 +54,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class AbandonRequestTest
+public class AbandonRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-    
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a AbandonRequest with controls
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/add/AddRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/add/AddRequestTest.java
index 4a84375..fadf78f 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/add/AddRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/add/AddRequestTest.java
@@ -38,14 +38,12 @@
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
 import org.apache.directory.shared.ldap.codec.decorators.AddRequestDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.entry.Entry;
 import org.apache.directory.shared.ldap.model.entry.EntryAttribute;
 import org.apache.directory.shared.ldap.model.entry.Value;
@@ -62,13 +60,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class AddRequestTest
+public class AddRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test the decoding of a AddRequest
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/add/AddResponseTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/add/AddResponseTest.java
index 2aef43f..70c4de9 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/add/AddResponseTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/add/AddResponseTest.java
@@ -33,13 +33,11 @@
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.AddResponseDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.AddResponse;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.Message;
@@ -54,14 +52,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class AddResponseTest
+public class AddResponseTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-    
-
     /**
      * Test the decoding of a AddResponse
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestPerfTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestPerfTest.java
index 30e5e42..0cd50cd 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestPerfTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestPerfTest.java
@@ -32,16 +32,13 @@
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.DecoderException;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.BindRequest;
 import org.apache.directory.shared.ldap.model.message.BindRequestImpl;
 import org.apache.directory.shared.ldap.model.message.Control;
-import org.apache.directory.shared.ldap.model.message.controls.AbstractControl;
 import org.apache.directory.shared.ldap.model.message.controls.OpaqueControl;
 import org.apache.directory.shared.ldap.model.name.Dn;
 import org.apache.directory.shared.util.Strings;
@@ -55,13 +52,9 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class BindRequestPerfTest
+@Ignore( "Ignore performance tests: should not be with integration tests" )
+public class BindRequestPerfTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test the decoding of a BindRequest with Simple authentication and no
      * controls
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestTest.java
index 2da8200..d19aa45 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindRequestTest.java
@@ -20,7 +20,7 @@
 package org.apache.directory.shared.ldap.codec.bind;
 
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertEquals; 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -34,14 +34,12 @@
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
 import org.apache.directory.shared.ldap.codec.decorators.BindRequestDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.BindRequest;
 import org.apache.directory.shared.ldap.model.message.BindResponseImpl;
 import org.apache.directory.shared.ldap.model.message.Control;
@@ -57,13 +55,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class BindRequestTest
+public class BindRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test the decoding of a BindRequest with Simple authentication and no
      * controls
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindResponseTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindResponseTest.java
index 5ab0af1..d020381 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindResponseTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/bind/BindResponseTest.java
@@ -34,14 +34,12 @@
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.controls.search.pagedSearch.PagedResultsDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.BindResponseDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.MessageDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.BindResponse;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.Message;
@@ -56,13 +54,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class BindResponseTest
+public class BindResponseTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test the decoding of a BindResponse
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareRequestTest.java
index e0f639f..3696fd2 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareRequestTest.java
@@ -35,12 +35,10 @@
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.model.message.CompareRequest;
 import org.apache.directory.shared.ldap.model.message.CompareResponseImpl;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
 import org.apache.directory.shared.ldap.codec.decorators.CompareRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.Message;
 import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
@@ -56,14 +54,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class CompareRequestTest
+public class CompareRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-    
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a full CompareRequest
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareResponseTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareResponseTest.java
index 4fe4ee5..3853e62 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareResponseTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/compare/CompareResponseTest.java
@@ -32,12 +32,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.CompareResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.CompareResponse;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
@@ -53,13 +51,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class CompareResponseTest
+public class CompareResponseTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test the decoding of a CompareResponse
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/del/DelRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/del/DelRequestTest.java
index 47fd3a4..36165b1 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/del/DelRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/del/DelRequestTest.java
@@ -32,13 +32,11 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
 import org.apache.directory.shared.ldap.codec.decorators.DeleteRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.*;
 import org.apache.directory.shared.util.Strings;
 import org.junit.Test;
@@ -52,14 +50,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class DelRequestTest
+public class DelRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-    
-
     /**
      * Test the decoding of a full DelRequest
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/del/DelResponseTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/del/DelResponseTest.java
index 8a58fb4..c8b77d9 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/del/DelResponseTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/del/DelResponseTest.java
@@ -32,12 +32,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.DeleteResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.DeleteResponse;
 import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
@@ -53,13 +51,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class DelResponseTest
+public class DelResponseTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test the decoding of a DelResponse
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedRequestTest.java
index 7fbf113..875edfe 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedRequestTest.java
@@ -32,12 +32,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.ExtendedRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.ExtendedRequest;
 import org.apache.directory.shared.util.Strings;
@@ -52,14 +50,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class ExtendedRequestTest
+public class ExtendedRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-    
-
     /**
      * Test the decoding of a full ExtendedRequest
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedResponseTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedResponseTest.java
index 731f1aa..46c2765 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedResponseTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/extended/ExtendedResponseTest.java
@@ -32,12 +32,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.ExtendedResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.ExtendedResponse;
 import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
@@ -53,14 +51,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class ExtendedResponseTest
+public class ExtendedResponseTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    LdapCodecService codec = new DefaultLdapCodecService();
-    
-
     /**
      * Test the decoding of a full ExtendedResponse
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/intermediate/IntermediateResponseTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/intermediate/IntermediateResponseTest.java
index 09e3f9f..07e1ded 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/intermediate/IntermediateResponseTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/intermediate/IntermediateResponseTest.java
@@ -32,12 +32,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.IntermediateResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.IntermediateResponse;
 import org.apache.directory.shared.util.Strings;
@@ -52,15 +50,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class IntermediateResponseTest
+public class IntermediateResponseTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a full IntermediateResponse
      */
@@ -182,6 +173,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
@@ -263,6 +255,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyRequestTest.java
index 5519a2e..a54fb93 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyRequestTest.java
@@ -33,13 +33,11 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
 import org.apache.directory.shared.ldap.codec.decorators.ModifyRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.entry.EntryAttribute;
 import org.apache.directory.shared.ldap.model.entry.Modification;
 import org.apache.directory.shared.ldap.model.exception.LdapException;
@@ -60,15 +58,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class ModifyRequestTest
+public class ModifyRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a ModifyRequest
      */
@@ -1206,6 +1197,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyResponseTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyResponseTest.java
index 3d6ae9d..3bd4de9 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyResponseTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modify/ModifyResponseTest.java
@@ -32,12 +32,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.ModifyResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.ModifyResponse;
 import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
@@ -53,15 +51,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class ModifyResponseTest
+public class ModifyResponseTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a ModifyResponse
      */
@@ -199,6 +190,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNRequestTest.java
index afc3323..3bf3be8 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNRequestTest.java
@@ -32,13 +32,11 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
 import org.apache.directory.shared.ldap.codec.decorators.ModifyDnRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.Message;
 import org.apache.directory.shared.ldap.model.message.ModifyDnRequest;
@@ -56,15 +54,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class ModifyDNRequestTest
+public class ModifyDNRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a full ModifyDNRequest
      */
@@ -367,6 +358,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
@@ -529,6 +521,7 @@
 
         assertTrue( modifyDnRequest.hasControl( "2.16.840.1.113730.3.4.2" ) );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNResponseTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNResponseTest.java
index 565f9c8..0891007 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNResponseTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/modifyDn/ModifyDNResponseTest.java
@@ -32,12 +32,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.ModifyDnResponseDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.ModifyDnResponse;
 import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
@@ -53,15 +51,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class ModifyDNResponseTest
+public class ModifyDNResponseTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a ModifyDNResponse
      */
@@ -202,6 +193,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/osgi/AbstractCodecServiceTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/osgi/AbstractCodecServiceTest.java
new file mode 100644
index 0000000..5d1dba7
--- /dev/null
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/osgi/AbstractCodecServiceTest.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.shared.ldap.codec.osgi;
+
+
+import org.apache.directory.shared.ldap.codec.LdapEncoder;
+import org.apache.directory.shared.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/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java
index 10d754d..bd8aedb 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestMatchingRuleAssertionTest.java
@@ -37,11 +37,9 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
 import org.apache.directory.shared.ldap.model.filter.ExprNode;
 import org.apache.directory.shared.ldap.model.filter.ExtensibleNode;
@@ -63,14 +61,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SearchRequestMatchingRuleAssertionTest
+public class SearchRequestMatchingRuleAssertionTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
     /** An oid normalizer map */
     static Map<String, OidNormalizer> oids = new HashMap<String, OidNormalizer>();
 
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestSubstringTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestSubstringTest.java
index 57f288e..fe135ab 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestSubstringTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestSubstringTest.java
@@ -35,12 +35,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
 import org.apache.directory.shared.ldap.model.filter.ExprNode;
 import org.apache.directory.shared.ldap.model.filter.SearchScope;
@@ -63,14 +61,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SearchRequestSubstringTest
+public class SearchRequestSubstringTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
     /** An oid normalizer map */
     static Map<String, OidNormalizer> oids = new HashMap<String, OidNormalizer>();
 
@@ -351,6 +343,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestTest.java
index 255dc4d..dc1c284 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchRequestTest.java
@@ -38,13 +38,11 @@
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.api.ResponseCarryingException;
 import org.apache.directory.shared.ldap.codec.controls.search.subentries.SubentriesDecorator;
 import org.apache.directory.shared.ldap.codec.decorators.SearchRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
 import org.apache.directory.shared.ldap.model.filter.AndNode;
 import org.apache.directory.shared.ldap.model.filter.ApproximateNode;
@@ -79,14 +77,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SearchRequestTest
+public class SearchRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
     /** An oid normalizer map */
     static Map<String, OidNormalizer> oids = new HashMap<String, OidNormalizer>();
 
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultDoneTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultDoneTest.java
index f4d75de..81e439c 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultDoneTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultDoneTest.java
@@ -32,12 +32,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.SearchResultDoneDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
 import org.apache.directory.shared.ldap.model.message.SearchResultDone;
@@ -53,15 +51,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SearchResultDoneTest
+public class SearchResultDoneTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a SearchResultDone
      */
@@ -197,6 +188,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultEntryTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultEntryTest.java
index ba68ea5..cb2316e 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultEntryTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultEntryTest.java
@@ -34,12 +34,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.SearchResultEntryDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.entry.Entry;
 import org.apache.directory.shared.ldap.model.entry.EntryAttribute;
 import org.apache.directory.shared.ldap.model.message.Control;
@@ -56,15 +54,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SearchResultEntryTest
+public class SearchResultEntryTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a SearchResultEntry
      */
@@ -1032,6 +1023,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
@@ -1223,6 +1215,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultReferenceTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultReferenceTest.java
index 3ec02a1..80525c1 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultReferenceTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/SearchResultReferenceTest.java
@@ -35,12 +35,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.SearchResultReferenceDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.Referral;
 import org.apache.directory.shared.ldap.model.message.SearchResultReference;
@@ -56,15 +54,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SearchResultReferenceTest
+public class SearchResultReferenceTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    LdapCodecService codec = new DefaultLdapCodecService();
-
-
     /**
      * Test the decoding of a SearchResultReference
      */
@@ -296,6 +287,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/EntryChangeControlTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/EntryChangeControlTest.java
index 1235388..90162e9 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/EntryChangeControlTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/EntryChangeControlTest.java
@@ -28,9 +28,8 @@
 import com.mycila.junit.concurrent.Concurrency;
 import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.controls.search.entryChange.EntryChangeDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.controls.ChangeType;
 import org.apache.directory.shared.ldap.model.message.controls.EntryChange;
 import org.apache.directory.shared.ldap.model.name.Dn;
@@ -46,10 +45,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class EntryChangeControlTest
+public class EntryChangeControlTest extends AbstractCodecServiceTest
 {
-    private LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test the decoding of a EntryChangeControl
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PSearchControlTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PSearchControlTest.java
index cbc3fb4..2838994 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PSearchControlTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PSearchControlTest.java
@@ -28,9 +28,8 @@
 import com.mycila.junit.concurrent.Concurrency;
 import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.controls.search.persistentSearch.PersistentSearchDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.controls.ChangeType;
 import org.apache.directory.shared.ldap.model.message.controls.PersistentSearch;
 import org.apache.directory.shared.util.Strings;
@@ -45,10 +44,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class PSearchControlTest
+public class PSearchControlTest extends AbstractCodecServiceTest
 {
-    private LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test encoding of a PSearchControl.
      * @throws Exception on error
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PagedSearchControlTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PagedSearchControlTest.java
index 0a88525..cdc2073 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PagedSearchControlTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/PagedSearchControlTest.java
@@ -30,9 +30,8 @@
 import com.mycila.junit.concurrent.Concurrency;
 import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.controls.search.pagedSearch.PagedResultsDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.controls.PagedResults;
 import org.apache.directory.shared.util.Strings;
 import org.junit.Test;
@@ -46,10 +45,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class PagedSearchControlTest
+public class PagedSearchControlTest extends AbstractCodecServiceTest
 {
-    private LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test encoding of a PagedSearchControl.
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/SubEntryControlTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/SubEntryControlTest.java
index 61d8707..a180bdc 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/SubEntryControlTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/search/controls/SubEntryControlTest.java
@@ -31,9 +31,8 @@
 import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.controls.search.subentries.SubentriesDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.controls.Subentries;
 import org.apache.directory.shared.util.Strings;
 import org.junit.Test;
@@ -47,10 +46,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SubEntryControlTest
+public class SubEntryControlTest extends AbstractCodecServiceTest
 {
-    private LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test the decoding of a SubEntryControl with a true visibility
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/unbind/UnBindRequestTest.java b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/unbind/UnBindRequestTest.java
index 1124b5e..b8e6e9d 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/unbind/UnBindRequestTest.java
+++ b/ldap-codec/src/test/java/org/apache/directory/shared/ldap/codec/unbind/UnBindRequestTest.java
@@ -32,12 +32,10 @@
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
-import org.apache.directory.shared.ldap.codec.LdapEncoder;
 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
 import org.apache.directory.shared.ldap.codec.api.CodecControl;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
 import org.apache.directory.shared.ldap.codec.decorators.UnbindRequestDecorator;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.model.message.Control;
 import org.apache.directory.shared.ldap.model.message.UnbindRequest;
 import org.apache.directory.shared.ldap.model.message.UnbindRequestImpl;
@@ -51,14 +49,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class UnBindRequestTest
+public class UnBindRequestTest extends AbstractCodecServiceTest
 {
-    /** The encoder instance */
-    private LdapEncoder encoder = new LdapEncoder();
-
-    /** The codec service */
-    private LdapCodecService codec = new DefaultLdapCodecService();
-
     /**
      * Test the decoding of a UnBindRequest with no controls
      */
@@ -164,6 +156,7 @@
 
         assertEquals( 1, controls.size() );
 
+        @SuppressWarnings("unchecked")
         CodecControl<Control> control = (org.apache.directory.shared.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()) );
diff --git a/ldap-extras/aci/pom.xml b/ldap-extras/aci/pom.xml
new file mode 100644
index 0000000..c23e51f
--- /dev/null
+++ b/ldap-extras/aci/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.shared</groupId>
+    <artifactId>shared-ldap-extras-parent</artifactId>
+    <version>1.0.0-M2-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>shared-ldap-extras-aci</artifactId>
+  <name>Apache Directory Shared LDAP Extras ACI</name>
+  <packaging>bundle</packaging>
+  <description>Extra Shared 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>shared-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-model</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>antlr-maven-plugin</artifactId>
+        <version>2.1</version>
+        <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.shared.ldap.aci*
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/ldap/src/checkstyle/suppressions.xml b/ldap-extras/aci/src/checkstyle/suppressions.xml
similarity index 100%
copy from ldap/src/checkstyle/suppressions.xml
copy to ldap-extras/aci/src/checkstyle/suppressions.xml
diff --git a/ldap/src/main/antlr/ACIItem.g b/ldap-extras/aci/src/main/antlr/ACIItem.g
similarity index 100%
rename from ldap/src/main/antlr/ACIItem.g
rename to ldap-extras/aci/src/main/antlr/ACIItem.g
diff --git a/ldap/src/main/antlr/ACIItemChecker.g b/ldap-extras/aci/src/main/antlr/ACIItemChecker.g
similarity index 100%
rename from ldap/src/main/antlr/ACIItemChecker.g
rename to ldap-extras/aci/src/main/antlr/ACIItemChecker.g
diff --git a/ldap/src/main/appended-resources/META-INF/LICENSE b/ldap-extras/aci/src/main/appended-resources/META-INF/LICENSE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/LICENSE
copy to ldap-extras/aci/src/main/appended-resources/META-INF/LICENSE
diff --git a/ldap/src/main/appended-resources/META-INF/NOTICE b/ldap-extras/aci/src/main/appended-resources/META-INF/NOTICE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/NOTICE
copy to ldap-extras/aci/src/main/appended-resources/META-INF/NOTICE
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACIItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACIItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemChecker.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemChecker.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemChecker.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemChecker.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemParser.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemParser.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemParser.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemParser.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemSyntaxChecker.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemSyntaxChecker.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemSyntaxChecker.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemSyntaxChecker.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACITuple.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACITuple.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACITuple.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ACITuple.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/GrantAndDenial.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/GrantAndDenial.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/GrantAndDenial.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/GrantAndDenial.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ItemFirstACIItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ItemFirstACIItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ItemFirstACIItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ItemFirstACIItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ItemPermission.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ItemPermission.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ItemPermission.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ItemPermission.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/MicroOperation.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/MicroOperation.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/MicroOperation.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/MicroOperation.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/Permission.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/Permission.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/Permission.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/Permission.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ProtectedItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ProtectedItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ProtectedItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ProtectedItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemChecker.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemChecker.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemChecker.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemChecker.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemCheckerLexer.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemCheckerLexer.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemCheckerLexer.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemCheckerLexer.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemLexer.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemLexer.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemLexer.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemLexer.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemParser.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemParser.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemParser.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemParser.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/UserClass.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/UserClass.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/UserClass.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/UserClass.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/UserFirstACIItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/UserFirstACIItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/UserFirstACIItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/UserFirstACIItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/UserPermission.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/UserPermission.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/UserPermission.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/UserPermission.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AbstractAttributeTypeProtectedItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AbstractAttributeTypeProtectedItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AbstractAttributeTypeProtectedItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AbstractAttributeTypeProtectedItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllAttributeValuesItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllAttributeValuesItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllAttributeValuesItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllAttributeValuesItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllUserAttributeTypesAndValuesItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllUserAttributeTypesAndValuesItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllUserAttributeTypesAndValuesItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllUserAttributeTypesAndValuesItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllUserAttributeTypesItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllUserAttributeTypesItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllUserAttributeTypesItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AllUserAttributeTypesItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeTypeItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeTypeItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeTypeItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeTypeItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeValueItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeValueItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeValueItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeValueItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/ClassesItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/ClassesItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/ClassesItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/ClassesItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/EntryItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/EntryItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/EntryItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/EntryItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxImmSubItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxImmSubItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxImmSubItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxImmSubItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountElem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountElem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountElem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountElem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RangeOfValuesItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RangeOfValuesItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RangeOfValuesItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RangeOfValuesItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByElem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByElem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByElem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByElem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByItem.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/SelfValueItem.java b/ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/SelfValueItem.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/SelfValueItem.java
rename to ldap-extras/aci/src/main/java/org/apache/directory/shared/ldap/aci/protectedItem/SelfValueItem.java
diff --git a/ldap/src/site/site.xml b/ldap-extras/aci/src/site/site.xml
similarity index 100%
copy from ldap/src/site/site.xml
copy to ldap-extras/aci/src/site/site.xml
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AllAttributeValuesTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AllAttributeValuesTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AllAttributeValuesTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AllAttributeValuesTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AttributeTypeTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AttributeTypeTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AttributeTypeTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AttributeTypeTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AttributeValueTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AttributeValueTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AttributeValueTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_AttributeValueTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_ClassesTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_ClassesTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_ClassesTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_ClassesTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_MaxImmSubTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_MaxImmSubTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_MaxImmSubTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_MaxImmSubTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_MaxValueCountTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_MaxValueCountTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_MaxValueCountTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_MaxValueCountTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_RangeOfValuesTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_RangeOfValuesTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_RangeOfValuesTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_RangeOfValuesTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_RestrictedByTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_RestrictedByTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_RestrictedByTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_RestrictedByTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_SelfValueTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_SelfValueTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_SelfValueTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/ProtectedItem_SelfValueTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/UserClass_NameTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/UserClass_NameTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/UserClass_NameTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/UserClass_NameTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/UserClass_SubtreeTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/UserClass_SubtreeTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/UserClass_SubtreeTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/UserClass_SubtreeTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeValueItemTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeValueItemTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeValueItemTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/AttributeValueItemTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/ClassesItemTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/ClassesItemTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/ClassesItemTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/ClassesItemTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxImmSubItemTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxImmSubItemTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxImmSubItemTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxImmSubItemTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountItemTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountItemTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountItemTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/MaxValueCountItemTest.java
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByItemTest.java b/ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByItemTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByItemTest.java
rename to ldap-extras/aci/src/test/java/org/apache/directory/shared/ldap/aci/protectedItem/RestrictedByItemTest.java
diff --git a/ldap/src/test/resources/log4j.properties b/ldap-extras/aci/src/test/resources/log4j.properties
similarity index 100%
copy from ldap/src/test/resources/log4j.properties
copy to ldap-extras/aci/src/test/resources/log4j.properties
diff --git a/ldap-extras/codec/pom.xml b/ldap-extras/codec/pom.xml
new file mode 100644
index 0000000..38eb21a
--- /dev/null
+++ b/ldap-extras/codec/pom.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT 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.shared</groupId>
+    <artifactId>shared-ldap-extras-parent</artifactId>
+    <version>1.0.0-M2-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>shared-ldap-extras-codec</artifactId>
+  <name>Apache Directory Shared LDAP 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>org.apache.directory.shared</groupId>
+      <artifactId>shared-ldap-codec</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>
+              org.apache.directory.shared.ldap.extras.controls,
+              org.apache.directory.shared.ldap.extras.extended
+            </Export-Package>
+            <Bundle-Activator>
+              org.apache.directory.shared.ldap.extras.ExtrasBundleActivator
+            </Bundle-Activator>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/ldap-extras/codec/src/checkstyle/suppressions.xml b/ldap-extras/codec/src/checkstyle/suppressions.xml
new file mode 100644
index 0000000..74a4604
--- /dev/null
+++ b/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/ldap/src/main/appended-resources/META-INF/LICENSE b/ldap-extras/codec/src/main/appended-resources/META-INF/LICENSE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/LICENSE
copy to ldap-extras/codec/src/main/appended-resources/META-INF/LICENSE
diff --git a/ldap/src/main/appended-resources/META-INF/NOTICE b/ldap-extras/codec/src/main/appended-resources/META-INF/NOTICE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/NOTICE
copy to ldap-extras/codec/src/main/appended-resources/META-INF/NOTICE
diff --git a/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/ExtrasBundleActivator.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/ExtrasBundleActivator.java
new file mode 100644
index 0000000..ae9e9dc
--- /dev/null
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/ExtrasBundleActivator.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.shared.ldap.extras;
+
+
+import org.apache.directory.shared.ldap.codec.api.ControlFactory;
+import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
+import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.api.UnsolicitedResponseFactory;
+import org.apache.directory.shared.ldap.extras.controls.PasswordPolicy;
+import org.apache.directory.shared.ldap.extras.controls.SyncDoneValue;
+import org.apache.directory.shared.ldap.extras.controls.SyncInfoValue;
+import org.apache.directory.shared.ldap.extras.controls.SyncModifyDn;
+import org.apache.directory.shared.ldap.extras.controls.SyncRequestValue;
+import org.apache.directory.shared.ldap.extras.controls.SyncStateValue;
+import org.apache.directory.shared.ldap.extras.controls.ppolicy_impl.PasswordPolicyFactory;
+import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncDoneValueFactory;
+import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncInfoValueFactory;
+import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncModifyDnFactory;
+import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncRequestValueFactory;
+import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncStateValueFactory;
+import org.apache.directory.shared.ldap.extras.extended.CancelRequest;
+import org.apache.directory.shared.ldap.extras.extended.CertGenerationRequest;
+import org.apache.directory.shared.ldap.extras.extended.GracefulDisconnect;
+import org.apache.directory.shared.ldap.extras.extended.GracefulShutdownRequest;
+import org.apache.directory.shared.ldap.extras.extended.StoredProcedureRequest;
+import org.apache.directory.shared.ldap.extras.extended.ads_impl.CancelFactory;
+import org.apache.directory.shared.ldap.extras.extended.ads_impl.CertGenerationFactory;
+import org.apache.directory.shared.ldap.extras.extended.ads_impl.GracefulDisconnectFactory;
+import org.apache.directory.shared.ldap.extras.extended.ads_impl.GracefulShutdownFactory;
+import org.apache.directory.shared.ldap.extras.extended.ads_impl.StoredProcedureFactory;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+
+/**
+ * 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 ServiceReference codecServiceRef;
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void start( BundleContext context ) throws Exception
+    {
+        codecServiceRef = context.getServiceReference( LdapCodecService.class.getName() );
+        LdapCodecService codec = ( LdapCodecService ) context.getService( codecServiceRef );
+        registerExtrasControls( codec );
+        registerExtrasExtendedOps( codec );
+    }
+    
+    
+    /**
+     * Registers all the extras controls present in this control pack.
+     *
+     * @param codec The codec service.
+     */
+    private void registerExtrasControls( LdapCodecService codec )
+    {
+        ControlFactory<?,?> factory = new SyncDoneValueFactory( codec );
+        codec.registerControl( factory );
+        
+        factory = new SyncInfoValueFactory( codec );
+        codec.registerControl( factory );
+        
+        factory = new SyncModifyDnFactory( codec );
+        codec.registerControl( factory );
+        
+        factory = new SyncRequestValueFactory( codec );
+        codec.registerControl( factory );
+
+        factory = new SyncStateValueFactory( codec );
+        codec.registerControl( factory );
+        
+        factory = new PasswordPolicyFactory( codec );
+        codec.registerControl( factory );
+    }
+
+
+    /**
+     * Registers all the extras extended operations present in this control pack.
+     *
+     * @param codec The codec service.
+     */
+    private void registerExtrasExtendedOps( LdapCodecService codec )
+    {
+        // --------------------------------------------------------------------
+        // Register Extended Request Factories
+        // --------------------------------------------------------------------
+        
+        
+        ExtendedRequestFactory<?,?> extReqfactory = new CancelFactory();
+        codec.registerExtendedRequest( extReqfactory );
+        
+        extReqfactory = new CertGenerationFactory();
+        codec.registerExtendedRequest( extReqfactory );
+
+        extReqfactory = new GracefulShutdownFactory();
+        codec.registerExtendedRequest( extReqfactory );
+        
+        extReqfactory = new StoredProcedureFactory();
+        codec.registerExtendedRequest( extReqfactory );
+        
+        
+        // --------------------------------------------------------------------
+        // Register Unsolicited Response Factories
+        // --------------------------------------------------------------------
+        
+        
+        UnsolicitedResponseFactory<?> unsolicitedResponseFactory = new GracefulDisconnectFactory();
+        codec.registerUnsolicitedResponse( unsolicitedResponseFactory );
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void stop( BundleContext context ) throws Exception
+    {
+        LdapCodecService codec = ( LdapCodecService ) context.getService( codecServiceRef );
+        
+        codec.unregisterControl( SyncDoneValue.OID );
+        codec.unregisterControl( SyncInfoValue.OID );
+        codec.unregisterControl( SyncModifyDn.OID );
+        codec.unregisterControl( SyncRequestValue.OID );
+        codec.unregisterControl( SyncStateValue.OID );
+        codec.unregisterControl( PasswordPolicy.OID );
+        
+        codec.unregisterExtendedRequest( CancelRequest.EXTENSION_OID );
+        codec.unregisterExtendedRequest( CertGenerationRequest.EXTENSION_OID );
+        codec.unregisterExtendedRequest( GracefulShutdownRequest.EXTENSION_OID );
+        codec.unregisterExtendedRequest( StoredProcedureRequest.EXTENSION_OID );
+        
+        codec.unregisterUnsolicitedResponse( GracefulDisconnect.EXTENSION_OID );
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicy.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicy.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicy.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicy.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyErrorEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyErrorEnum.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyErrorEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyErrorEnum.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyImpl.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyImpl.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyImpl.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyImpl.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyResponse.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyResponse.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyResponse.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyResponse.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyResponseImpl.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyResponseImpl.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyResponseImpl.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/PasswordPolicyResponseImpl.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncDoneValue.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncDoneValue.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncDoneValue.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncDoneValue.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncDoneValueImpl.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncDoneValueImpl.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncDoneValueImpl.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncDoneValueImpl.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncInfoValue.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncInfoValue.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncInfoValue.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncInfoValue.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncInfoValueImpl.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncInfoValueImpl.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncInfoValueImpl.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncInfoValueImpl.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDn.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDn.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDn.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDn.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDnImpl.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDnImpl.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDnImpl.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDnImpl.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDnType.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDnType.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDnType.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncModifyDnType.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncRequestValue.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncRequestValue.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncRequestValue.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncRequestValue.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncRequestValueImpl.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncRequestValueImpl.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncRequestValueImpl.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncRequestValueImpl.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateTypeEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateTypeEnum.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateTypeEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateTypeEnum.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateValue.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateValue.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateValue.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateValue.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateValueImpl.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateValueImpl.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateValueImpl.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SyncStateValueImpl.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SynchronizationInfoEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SynchronizationInfoEnum.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SynchronizationInfoEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SynchronizationInfoEnum.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SynchronizationModeEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SynchronizationModeEnum.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SynchronizationModeEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/SynchronizationModeEnum.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PPolicyInit.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PPolicyInit.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PPolicyInit.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PPolicyInit.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyDecorator.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyDecorator.java
similarity index 96%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyDecorator.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyDecorator.java
index 46f1c35..782fa1c 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyDecorator.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyDecorator.java
@@ -30,8 +30,8 @@
 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
 import org.apache.directory.shared.ldap.extras.controls.PasswordPolicy;
 import org.apache.directory.shared.ldap.extras.controls.PasswordPolicyResponse;
 import org.apache.directory.shared.ldap.extras.controls.PasswordPolicyImpl;
@@ -195,16 +195,16 @@
         sb.append( "  PasswordPolicyResponse control :\n" );
         sb.append( "   oid          : '" ).append( getOid() ).append( '\n' );
         
-        if ( getResponse().getTimeBeforeExpiration() >= 0 )
+        if ( hasResponse() && getResponse().getTimeBeforeExpiration() >= 0 )
         {
             sb.append( "   timeBeforeExpiration          : '" ).append( getResponse().getTimeBeforeExpiration() ).append( '\n' );
         }
-        else if ( getResponse().getGraceAuthNsRemaining() >= 0 )
+        else if ( hasResponse() && getResponse().getGraceAuthNsRemaining() >= 0 )
         {
             sb.append( "   graceAuthNsRemaining          : '" ).append( getResponse().getGraceAuthNsRemaining() ).append( '\n' );
         }
 
-        if ( getResponse().getPasswordPolicyError() != null )
+        if ( hasResponse() && getResponse().getPasswordPolicyError() != null )
         {
             sb.append( "   ppolicyError          : '" ).append( getResponse().getPasswordPolicyError().toString() ).append( '\n' );
         }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyFactory.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyFactory.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyFactory.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyGrammar.java
similarity index 96%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyGrammar.java
index b1b671c..1812a23 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyGrammar.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyGrammar.java
@@ -49,12 +49,13 @@
  *          
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class PasswordPolicyGrammar extends AbstractGrammar
+public class PasswordPolicyGrammar extends AbstractGrammar<PasswordPolicyContainer>
 {
     /** PasswordPolicyResponseControlGrammar singleton instance */
     private static final PasswordPolicyGrammar INSTANCE = new PasswordPolicyGrammar();
 
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     private PasswordPolicyGrammar()
     {
         setName( PasswordPolicyGrammar.class.getName() );
@@ -112,7 +113,7 @@
     }
 
 
-    public static Grammar getInstance()
+    public static Grammar<PasswordPolicyContainer> getInstance()
     {
         return INSTANCE;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyStates.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyStates.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyStates.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyStates.java
index b68c62b..63285de 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyStates.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyStates.java
@@ -50,7 +50,7 @@
     /**
      * {@inheritDoc}
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<?> grammar )
     {
         if( grammar instanceof PasswordPolicyGrammar )
         {
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTags.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTags.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTags.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTags.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreError.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreError.java
similarity index 98%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreError.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreError.java
index afd2993..26abc8d 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreError.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreError.java
@@ -30,6 +30,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
+@SuppressWarnings("rawtypes")
 public class StoreError extends AbstractReadInteger
 {
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreGraceAuthsRemaining.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreGraceAuthsRemaining.java
similarity index 98%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreGraceAuthsRemaining.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreGraceAuthsRemaining.java
index 66d0b51..2fd5c35 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreGraceAuthsRemaining.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreGraceAuthsRemaining.java
@@ -29,6 +29,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
+@SuppressWarnings("rawtypes")
 public class StoreGraceAuthsRemaining extends AbstractReadInteger
 {
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreTimeBeforeExpiration.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreTimeBeforeExpiration.java
similarity index 98%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreTimeBeforeExpiration.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreTimeBeforeExpiration.java
index 39b9ab4..863ebb5 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreTimeBeforeExpiration.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/StoreTimeBeforeExpiration.java
@@ -29,6 +29,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
+@SuppressWarnings("rawtypes")
 public class StoreTimeBeforeExpiration extends AbstractReadInteger
 {
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueDecorator.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueDecorator.java
similarity index 98%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueDecorator.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueDecorator.java
index f58ac21..bbc199c 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueDecorator.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueDecorator.java
@@ -31,7 +31,7 @@
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.extras.controls.SyncDoneValue;
 import org.apache.directory.shared.ldap.extras.controls.SyncDoneValueImpl;
 import org.apache.directory.shared.util.Strings;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueFactory.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueFactory.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueFactory.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueGrammar.java
similarity index 88%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueGrammar.java
index 8a4b62f..3a00e39 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueGrammar.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueGrammar.java
@@ -50,7 +50,7 @@
  *  
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class SyncDoneValueGrammar extends AbstractGrammar
+public final class SyncDoneValueGrammar extends AbstractGrammar<SyncDoneValueContainer>
 {
 
     /** the logger */
@@ -68,6 +68,7 @@
      * Creates a new instance of SyncDoneValueControlGrammar.
      *
      */
+    @SuppressWarnings("unchecked")
     private SyncDoneValueGrammar()
     {
         setName( SyncDoneValueGrammar.class.getName() );
@@ -81,7 +82,7 @@
          *     
          * Initialize the syncDoneValue object
          */
-        super.transitions[SyncDoneValueStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
+        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" )
             {
@@ -99,9 +100,9 @@
          *    ....
          * }
          */
-        super.transitions[SyncDoneValueStatesEnum.SYNC_DONE_VALUE_SEQUENCE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            SyncDoneValueStatesEnum.SYNC_DONE_VALUE_SEQUENCE_STATE, SyncDoneValueStatesEnum.COOKIE_STATE,
-            UniversalTag.OCTET_STRING.getValue(), 
+        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
@@ -158,7 +159,8 @@
          *    refreshDeletes BOOLEAN DEFAULT FALSE
          * }
          */
-        super.transitions[SyncDoneValueStatesEnum.COOKIE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] = new GrammarTransition(
+        super.transitions[SyncDoneValueStatesEnum.COOKIE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] = 
+            new GrammarTransition<SyncDoneValueContainer>(
             SyncDoneValueStatesEnum.COOKIE_STATE, SyncDoneValueStatesEnum.REFRESH_DELETES_STATE,
             UniversalTag.BOOLEAN.getValue(), refreshDeletesTagAction );
         
@@ -169,17 +171,16 @@
          *    refreshDeletes BOOLEAN DEFAULT FALSE
          * }
          */
-        super.transitions[SyncDoneValueStatesEnum.SYNC_DONE_VALUE_SEQUENCE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] = new GrammarTransition(
-            SyncDoneValueStatesEnum.SYNC_DONE_VALUE_SEQUENCE_STATE, SyncDoneValueStatesEnum.REFRESH_DELETES_STATE,
-            UniversalTag.BOOLEAN.getValue(), refreshDeletesTagAction );
-
+        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 getInstance()
+    public static Grammar<SyncDoneValueContainer> getInstance()
     {
         return INSTANCE;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueStatesEnum.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueStatesEnum.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueDecorator.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueDecorator.java
similarity index 99%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueDecorator.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueDecorator.java
index 66826cd..b186bdd 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueDecorator.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueDecorator.java
@@ -32,8 +32,8 @@
 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
 import org.apache.directory.shared.ldap.extras.controls.SyncInfoValue;
 import org.apache.directory.shared.ldap.extras.controls.SyncInfoValueImpl;
 import org.apache.directory.shared.ldap.extras.controls.SynchronizationInfoEnum;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueFactory.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueFactory.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueFactory.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueGrammar.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueGrammar.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueStatesEnum.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueStatesEnum.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueTags.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueTags.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueTags.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueTags.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnDecorator.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnDecorator.java
similarity index 99%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnDecorator.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnDecorator.java
index f11f6c4..b166186 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnDecorator.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnDecorator.java
@@ -32,7 +32,7 @@
 import org.apache.directory.shared.asn1.util.Asn1StringUtils;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.extras.controls.SyncModifyDn;
 import org.apache.directory.shared.ldap.extras.controls.SyncModifyDnImpl;
 import org.apache.directory.shared.ldap.extras.controls.SyncModifyDnType;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnFactory.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnFactory.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnFactory.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnGrammar.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnGrammar.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnStatesEnum.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnStatesEnum.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnTags.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnTags.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnTags.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnTags.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueDecorator.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueDecorator.java
similarity index 98%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueDecorator.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueDecorator.java
index 17b250f..a270425 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueDecorator.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueDecorator.java
@@ -31,7 +31,7 @@
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.extras.controls.SyncRequestValue;
 import org.apache.directory.shared.ldap.extras.controls.SyncRequestValueImpl;
 import org.apache.directory.shared.ldap.extras.controls.SynchronizationModeEnum;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueFactory.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueFactory.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueFactory.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueGrammar.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueGrammar.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueStatesEnum.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueStatesEnum.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueDecorator.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueDecorator.java
similarity index 98%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueDecorator.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueDecorator.java
index f43771d..f8bdcc9 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueDecorator.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueDecorator.java
@@ -30,8 +30,8 @@
 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
 import org.apache.directory.shared.asn1.ber.tlv.Value;
 import org.apache.directory.shared.i18n.I18n;
+import org.apache.directory.shared.ldap.codec.api.ControlDecorator;
 import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
-import org.apache.directory.shared.ldap.codec.controls.ControlDecorator;
 import org.apache.directory.shared.ldap.extras.controls.SyncStateTypeEnum;
 import org.apache.directory.shared.ldap.extras.controls.SyncStateValue;
 import org.apache.directory.shared.ldap.extras.controls.SyncStateValueImpl;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueFactory.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueFactory.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueFactory.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueGrammar.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueGrammar.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueStatesEnum.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueStatesEnum.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelRequest.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelRequest.java
similarity index 86%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelRequest.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelRequest.java
index a17b136..b2ea8ef 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelRequest.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelRequest.java
@@ -62,7 +62,6 @@
 
 
     /**
-     * 
      * Creates a new instance of CancelRequest.
      *
      * @param messageId the message id
@@ -78,6 +77,15 @@
 
 
     /**
+     * Creates a new instance of CancelRequest.
+     */
+    public CancelRequest()
+    {
+        setRequestName( EXTENSION_OID );
+    }
+
+
+    /**
      * Sets the extended request's <b>requestValue</b> portion of the PDU.
      * 
      * @param payload byte array of data encapsulating ext. req. parameters
@@ -116,6 +124,32 @@
         return ( ExtendedResponse ) getResultResponse();
     }
 
+    
+    /**
+     *  @return The id of the Message to cancel.
+     */
+    public int getCancelId()
+    {
+        return cancelId;
+    }
+    
+    
+    /**
+     * Sets the message to cancel by id.
+     *
+     * @param cancelId The id of the message to cancel.
+     */
+    public void setCancelId( int cancelId )
+    {
+        this.cancelId = cancelId;
+        
+        // clear the request value if it was previously computed for the old value
+        if ( requestValue != null )
+        {
+            requestValue = null;
+        }
+    }
+    
 
     /**
      * {@inheritDoc}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelResponse.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelResponse.java
similarity index 94%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelResponse.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelResponse.java
index 986dd45..e40352c 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelResponse.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CancelResponse.java
@@ -74,6 +74,14 @@
     }
 
 
+    public CancelResponse()
+    {
+        super( CancelRequest.EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
     // ------------------------------------------------------------------------
     // ExtendedResponse Interface Method Implementations
     // ------------------------------------------------------------------------
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationRequest.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationRequest.java
similarity index 96%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationRequest.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationRequest.java
index f3f4a30..4f965af 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationRequest.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationRequest.java
@@ -54,7 +54,6 @@
 
 
     /**
-     * 
      * Creates a new instance of CertGenerationRequest.
      *
      * @param messageId the message id
@@ -76,6 +75,16 @@
     }
 
 
+    /**
+     * Creates a new instance of CertGenerationRequest.
+     */
+    public CertGenerationRequest()
+    {
+        setRequestName( EXTENSION_OID );
+        this.certGenObj = new CertGenerationObject();
+    }
+
+
     public void setequestValue( byte[] requestValue )
     {
         CertGenerationDecoder decoder = new CertGenerationDecoder();
@@ -195,5 +204,4 @@
     {
         certGenObj.setKeyAlgorithm( keyAlgorithm );
     }
-
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationResponse.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationResponse.java
similarity index 95%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationResponse.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationResponse.java
index 925656c..0cad5f2 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationResponse.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CertGenerationResponse.java
@@ -70,6 +70,14 @@
     }
 
 
+    public CertGenerationResponse()
+    {
+        super( EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
     // ------------------------------------------------------------------------
     // ExtendedResponse Interface Method Implementations
     // ------------------------------------------------------------------------
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulDisconnect.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulDisconnect.java
similarity index 92%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulDisconnect.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulDisconnect.java
index 4a5796a..b87acdc 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulDisconnect.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulDisconnect.java
@@ -42,7 +42,7 @@
 /**
  * An unsolicited notification, extended response, intended for notifying
  * clients of upcoming disconnection due to intended service windows. Unlike the
- * {@link NoticeOfDisconnect} this response contains additional information about
+ * {@link org.apache.directory.shared.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.
  * 
@@ -95,6 +95,16 @@
 
     /**
      * Instantiates a new graceful disconnect.
+     */
+    public GracefulDisconnect()
+    {
+        super( 0, EXTENSION_OID );
+        this.responseValue = null;
+    }
+
+
+    /**
+     * Instantiates a new graceful disconnect.
      *
      * @param timeOffline the offline time after disconnect, in minutes
      * @param delay the delay before disconnect, in seconds
@@ -203,12 +213,21 @@
 
 
     /**
-     * Sets the reponse OID specific encoded response values.
+     * Sets the response OID specific encoded response values.
      * 
      * @param responseValue the response specific encoded response values.
      */
     public void setResponseValue( byte[] responseValue )
     {
+        if ( responseValue == null )
+        {
+            this.responseValue = null;
+            this.delay = 0;
+            this.timeOffline = 0;
+            this.replicatedContexts = new ReferralImpl();
+            return;
+        }
+        
         ByteBuffer bb = ByteBuffer.wrap( responseValue );
         GracefulDisconnectContainer container = new GracefulDisconnectContainer();
         Asn1Decoder decoder = new Asn1Decoder();
@@ -232,15 +251,8 @@
             replicatedContexts.addLdapUrl( ldapUrl.toString() );
         }
 
-        if ( responseValue != null )
-        {
-            this.responseValue = new byte[responseValue.length];
-            System.arraycopy( responseValue, 0, this.responseValue, 0, responseValue.length );
-        }
-        else
-        {
-            this.responseValue = null;
-        }
+        this.responseValue = new byte[responseValue.length];
+        System.arraycopy( responseValue, 0, this.responseValue, 0, responseValue.length );
     }
 
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownRequest.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownRequest.java
similarity index 96%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownRequest.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownRequest.java
index fb2ca53..6807728 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownRequest.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownRequest.java
@@ -82,6 +82,17 @@
      * Instantiates a new graceful shutdown request.
      *
      * @param messageId the message id
+     */
+    public GracefulShutdownRequest()
+    {
+        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
      */
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownResponse.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownResponse.java
similarity index 94%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownResponse.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownResponse.java
index 73ff5af..59d7ccf 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownResponse.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/GracefulShutdownResponse.java
@@ -88,6 +88,17 @@
     }
 
 
+    /**
+     * Instantiates a new graceful shutdown response.
+     */
+    public GracefulShutdownResponse()
+    {
+        super( EXTENSION_OID );
+        super.getLdapResult().setMatchedDn( null );
+        super.getLdapResult().setResultCode( ResultCodeEnum.SUCCESS );
+    }
+
+
     // ------------------------------------------------------------------------
     // ExtendedResponse Interface Method Implementations
     // ------------------------------------------------------------------------
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/LaunchDiagnosticUiRequest.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/LaunchDiagnosticUiRequest.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/LaunchDiagnosticUiRequest.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/LaunchDiagnosticUiRequest.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/LaunchDiagnosticUiResponse.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/LaunchDiagnosticUiResponse.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/LaunchDiagnosticUiResponse.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/LaunchDiagnosticUiResponse.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureRequest.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureRequest.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureRequest.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureRequest.java
index 1d73baf..e12614a 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureRequest.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureRequest.java
@@ -75,6 +75,16 @@
 
     /**
      * Instantiates a new stored procedure request.
+     */
+    public StoredProcedureRequest()
+    {
+        this.setRequestName( EXTENSION_OID );
+        this.procedure = new StoredProcedure();
+    }
+
+
+    /**
+     * Instantiates a new stored procedure request.
      *
      * @param messageId the message id
      * @param procedure the procedure
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureResponse.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureResponse.java
similarity index 91%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureResponse.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureResponse.java
index ec774e7..5e96c33 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureResponse.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/StoredProcedureResponse.java
@@ -47,4 +47,13 @@
     {
         super( messageId, EXTENSION_OID );
     }
+
+    
+    /**
+     * Instantiates a new stored procedure response.
+     */
+    public StoredProcedureResponse()
+    {
+        super( EXTENSION_OID );
+    }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/Cancel.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/Cancel.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/Cancel.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/Cancel.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelDecoder.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelDecoder.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelDecoder.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelDecoder.java
diff --git a/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelFactory.java
new file mode 100644
index 0000000..f2903d0
--- /dev/null
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelFactory.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.shared.ldap.extras.extended.ads_impl;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
+import org.apache.directory.shared.ldap.extras.extended.CancelRequest;
+import org.apache.directory.shared.ldap.extras.extended.CancelResponse;
+
+
+/**
+ * An {@link ExtendedRequestFactory} for creating cancel extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CancelFactory implements ExtendedRequestFactory<CancelRequest, CancelResponse>
+{
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return CancelRequest.EXTENSION_OID;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public CancelRequest newRequest()
+    {
+        return new CancelRequest();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CancelResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        CancelResponse response = new CancelResponse();
+        response.setResponseValue( encodedValue );
+        return response;
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelGrammar.java
similarity index 91%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelGrammar.java
index acbc486..ade2659 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelGrammar.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelGrammar.java
@@ -50,7 +50,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class CancelGrammar extends AbstractGrammar
+public final class CancelGrammar extends AbstractGrammar<CancelContainer>
 {
     /** The logger */
     static final Logger LOG = LoggerFactory.getLogger( CancelGrammar.class );
@@ -59,12 +59,13 @@
     static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
     /** The instance of grammar. CancelGrammar is a singleton */
-    private static Grammar instance = new CancelGrammar();
+    private static Grammar<CancelContainer> instance = new CancelGrammar();
 
 
     /**
      * Creates a new GracefulDisconnectGrammar object.
      */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     private CancelGrammar()
     {
         setName( CancelGrammar.class.getName() );
@@ -80,11 +81,10 @@
          * Creates the Cancel object
          */
         super.transitions[CancelStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
-            new GrammarTransition( CancelStatesEnum.START_STATE,
+            new GrammarTransition<CancelContainer>( CancelStatesEnum.START_STATE,
                                     CancelStatesEnum.CANCEL_SEQUENCE_STATE, 
                                     UniversalTag.SEQUENCE.getValue(),
-                new GrammarAction(
-                "Init Cancel" )
+                new GrammarAction( "Init Cancel" )
             {
                 public void action( Asn1Container container )
                 {
@@ -104,7 +104,7 @@
          * Set the cancelId value into the Cancel object.    
          */
         super.transitions[CancelStatesEnum.CANCEL_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] = 
-            new GrammarTransition( CancelStatesEnum.CANCEL_SEQUENCE_STATE,
+            new GrammarTransition<CancelContainer>( CancelStatesEnum.CANCEL_SEQUENCE_STATE,
                                     CancelStatesEnum.CANCEL_ID_STATE, 
                                     UniversalTag.INTEGER.getValue(), 
                 new GrammarAction( "Stores CancelId" )
@@ -142,7 +142,7 @@
      * 
      * @return An instance on this grammar
      */
-    public static Grammar getInstance()
+    public static Grammar<CancelContainer> getInstance()
     {
         return instance;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelStatesEnum.java
similarity index 93%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelStatesEnum.java
index 60c326e..17ed0b5 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelStatesEnum.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelStatesEnum.java
@@ -71,14 +71,9 @@
      * @param grammar The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<CancelContainer> grammar )
     {
-        if ( grammar instanceof CancelGrammar )
-        {
-            return "CANCEL_GRAMMAR";
-        }
-
-        return "UNKNOWN GRAMMAR";
+        return "CANCEL_GRAMMAR";
     }
 
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationDecoder.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationDecoder.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationDecoder.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationDecoder.java
diff --git a/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationFactory.java
new file mode 100644
index 0000000..10d7a9f
--- /dev/null
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationFactory.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.shared.ldap.extras.extended.ads_impl;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
+import org.apache.directory.shared.ldap.extras.extended.CertGenerationRequest;
+import org.apache.directory.shared.ldap.extras.extended.CertGenerationResponse;
+
+
+/**
+ * An {@link ExtendedRequestFactory} for creating cancel extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class CertGenerationFactory 
+    implements ExtendedRequestFactory<CertGenerationRequest, CertGenerationResponse>
+{
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return CertGenerationRequest.EXTENSION_OID;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public CertGenerationRequest newRequest()
+    {
+        return new CertGenerationRequest();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public CertGenerationResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        CertGenerationResponse response = new CertGenerationResponse();
+        response.setResponseValue( encodedValue );
+        return response;
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationGrammar.java
similarity index 71%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationGrammar.java
index 8eda4b8..4b631a6 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationGrammar.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationGrammar.java
@@ -20,7 +20,6 @@
 package org.apache.directory.shared.ldap.extras.extended.ads_impl;
 
 
-import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
 import org.apache.directory.shared.asn1.ber.grammar.Grammar;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
@@ -53,7 +52,7 @@
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
 
-public class CertGenerationGrammar extends AbstractGrammar
+public class CertGenerationGrammar extends AbstractGrammar<CertGenerationContainer>
 {
 
     /** logger */
@@ -63,9 +62,10 @@
     static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
     /** The instance of grammar. CertGenerationObjectGrammar is a singleton */
-    private static Grammar instance = new CertGenerationGrammar();
+    private static Grammar<CertGenerationContainer> instance = new CertGenerationGrammar();
 
 
+    @SuppressWarnings("unchecked")
     public CertGenerationGrammar()
     {
         setName( CertGenerationGrammar.class.getName() );
@@ -81,15 +81,15 @@
          *     
          * Creates the CertGenerationObject object
          */
-        super.transitions[CertGenerationStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = new GrammarTransition(
+        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( "Init CertGenerationObject" )
+            UniversalTag.SEQUENCE.getValue(), new GrammarAction<CertGenerationContainer>( "Init CertGenerationObject" )
             {
-                public void action( Asn1Container container )
+                public void action( CertGenerationContainer container )
                 {
-                    CertGenerationContainer certGenContainer = ( CertGenerationContainer ) container;
                     CertGenerationObject certGenerationObject = new CertGenerationObject();
-                    certGenContainer.setCertGenerationObject( certGenerationObject );
+                    container.setCertGenerationObject( certGenerationObject );
                 }
             } );
 
@@ -102,14 +102,14 @@
          *     
          * Set the targetDN value into the CertGenerationObject instance.
          */
-        super.transitions[CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE, CertGenerationStatesEnum.TARGETDN_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new GrammarAction( "Set Cert Generation target Dn value" )
+        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( Asn1Container container ) throws DecoderException
+                public void action( CertGenerationContainer container ) throws DecoderException
                 {
-                    CertGenerationContainer certGenContainer = ( CertGenerationContainer ) container;
-                    Value value = certGenContainer.getCurrentTLV().getValue();
+                    Value value = container.getCurrentTLV().getValue();
 
                     String targetDN = Strings.utf8ToString(value.getData());
 
@@ -127,7 +127,7 @@
                             throw new DecoderException( msg );
                         }
                         
-                        certGenContainer.getCertGenerationObject().setTargetDN( targetDN );
+                        container.getCertGenerationObject().setTargetDN( targetDN );
                     }
                     else
                     {
@@ -148,14 +148,14 @@
          *     
          * Set the issuerDN value into the CertGenerationObject instance.
          */
-        super.transitions[CertGenerationStatesEnum.TARGETDN_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            CertGenerationStatesEnum.TARGETDN_STATE, CertGenerationStatesEnum.ISSUER_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction( "Set Cert Generation issuer Dn value" )
+        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( Asn1Container container ) throws DecoderException
+                public void action( CertGenerationContainer container ) throws DecoderException
                 {
-                    CertGenerationContainer certGenContainer = ( CertGenerationContainer ) container;
-                    Value value = certGenContainer.getCurrentTLV().getValue();
+                    Value value = container.getCurrentTLV().getValue();
 
                     String issuerDN = Strings.utf8ToString(value.getData());
 
@@ -173,7 +173,7 @@
                             throw new DecoderException( msg );
                         }
                         
-                        certGenContainer.getCertGenerationObject().setIssuerDN( issuerDN );
+                        container.getCertGenerationObject().setIssuerDN( issuerDN );
                     }
                 }
             } );
@@ -188,14 +188,14 @@
          *     
          * Set the subjectDN value into the CertGenerationObject instance.
          */
-        super.transitions[CertGenerationStatesEnum.ISSUER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            CertGenerationStatesEnum.ISSUER_STATE, CertGenerationStatesEnum.SUBJECT_STATE, UniversalTag.OCTET_STRING.getValue(),
-            new GrammarAction( "Set Cert Generation subject Dn value" )
+        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( Asn1Container container ) throws DecoderException
+                public void action( CertGenerationContainer container ) throws DecoderException
                 {
-                    CertGenerationContainer certGenContainer = ( CertGenerationContainer ) container;
-                    Value value = certGenContainer.getCurrentTLV().getValue();
+                    Value value = container.getCurrentTLV().getValue();
 
                     String subjectDN = Strings.utf8ToString(value.getData());
 
@@ -213,7 +213,7 @@
                             throw new DecoderException( msg );
                         }
 
-                        certGenContainer.getCertGenerationObject().setSubjectDN( subjectDN );
+                        container.getCertGenerationObject().setSubjectDN( subjectDN );
                     }
                     else
                     {
@@ -233,14 +233,15 @@
          *     
          * Set the key algorithm value into the CertGenerationObject instance.
          */
-        super.transitions[CertGenerationStatesEnum.SUBJECT_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = new GrammarTransition(
-            CertGenerationStatesEnum.SUBJECT_STATE, CertGenerationStatesEnum.KEY_ALGORITHM_STATE,
-            UniversalTag.OCTET_STRING.getValue(), new GrammarAction( "Set Cert Generation key algorithm value" )
+        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( Asn1Container container ) throws DecoderException
+                public void action( CertGenerationContainer container ) throws DecoderException
                 {
-                    CertGenerationContainer certGenContainer = ( CertGenerationContainer ) container;
-                    Value value = certGenContainer.getCurrentTLV().getValue();
+                    Value value = container.getCurrentTLV().getValue();
 
                     String keyAlgorithm = Strings.utf8ToString(value.getData());
 
@@ -251,10 +252,10 @@
 
                     if ( keyAlgorithm != null && ( keyAlgorithm.trim().length() > 0 ) )
                     {
-                        certGenContainer.getCertGenerationObject().setKeyAlgorithm( keyAlgorithm );
+                        container.getCertGenerationObject().setKeyAlgorithm( keyAlgorithm );
                     }
 
-                    certGenContainer.setGrammarEndAllowed( true );
+                    container.setGrammarEndAllowed( true );
                 }
             } );
 
@@ -266,7 +267,7 @@
      * 
      * @return An instance on this grammar
      */
-    public static Grammar getInstance()
+    public static Grammar<CertGenerationContainer> getInstance()
     {
         return instance;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationObject.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationObject.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationObject.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationObject.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationStatesEnum.java
similarity index 92%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationStatesEnum.java
index a7ea3a0..890dc54 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationStatesEnum.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationStatesEnum.java
@@ -62,14 +62,9 @@
      * @param grammar The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<CertGenerationContainer> grammar )
     {
-        if ( grammar instanceof CertGenerationGrammar )
-        {
-            return "CERT_GENERATION_GRAMMER";
-        }
-        
-        return "UNKNOWN GRAMMAR";
+        return "CERT_GENERATION_GRAMMER";
     }
 
     
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulAction.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulAction.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulAction.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulAction.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulActionConstants.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulActionConstants.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulActionConstants.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulActionConstants.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnect.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnect.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnect.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnect.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectDecoder.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectDecoder.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectDecoder.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectDecoder.java
diff --git a/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectFactory.java
new file mode 100644
index 0000000..b317ff7
--- /dev/null
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectFactory.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.shared.ldap.extras.extended.ads_impl;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
+import org.apache.directory.shared.ldap.codec.api.UnsolicitedResponseFactory;
+import org.apache.directory.shared.ldap.extras.extended.GracefulDisconnect;
+
+
+/**
+ * An {@link ExtendedRequestFactory} for creating cancel extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulDisconnectFactory implements UnsolicitedResponseFactory<GracefulDisconnect>
+{
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return GracefulDisconnect.EXTENSION_OID;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public GracefulDisconnect newRequest()
+    {
+        return new GracefulDisconnect();
+    }
+
+
+    public GracefulDisconnect newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        return new GracefulDisconnect( encodedValue );
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectGrammar.java
similarity index 68%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectGrammar.java
index 4c1a195..742b9d2 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectGrammar.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectGrammar.java
@@ -21,9 +21,7 @@
 
 
 import org.apache.directory.shared.asn1.DecoderException;
-import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
-import org.apache.directory.shared.asn1.ber.grammar.Grammar;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
 import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
@@ -59,7 +57,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class GracefulDisconnectGrammar extends AbstractGrammar
+public final class GracefulDisconnectGrammar extends AbstractGrammar<GracefulDisconnectContainer>
 {
     /** The logger */
     static final Logger LOG = LoggerFactory.getLogger( GracefulDisconnectGrammar.class );
@@ -68,18 +66,18 @@
     static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
     /** The instance of grammar. GracefulDisconnectnGrammar is a singleton */
-    private static Grammar instance = new GracefulDisconnectGrammar();
+    private static GracefulDisconnectGrammar instance = new GracefulDisconnectGrammar();
 
 
     /**
      * The action used to store a Time Offline.
      */
-    private GrammarAction storeDelay = new GrammarAction( "Set Graceful Disconnect Delay" )
+    private GrammarAction<GracefulDisconnectContainer> storeDelay = 
+        new GrammarAction<GracefulDisconnectContainer>( "Set Graceful Disconnect Delay" )
     {
-        public void action( Asn1Container container ) throws DecoderException
+        public void action( GracefulDisconnectContainer container ) throws DecoderException
         {
-            GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
-            Value value = gracefulDisconnectContainer.getCurrentTLV().getValue();
+            Value value = container.getCurrentTLV().getValue();
     
             try
             {
@@ -90,8 +88,8 @@
                     LOG.debug( "Delay = " + delay );
                 }
     
-                gracefulDisconnectContainer.getGracefulDisconnect().setDelay( delay );
-                gracefulDisconnectContainer.setGrammarEndAllowed( true );
+                container.getGracefulDisconnect().setDelay( delay );
+                container.setGrammarEndAllowed( true );
             }
             catch ( IntegerDecoderException e )
             {
@@ -105,18 +103,18 @@
     /**
      * The action used to store a referral.
      */
-    private GrammarAction storeReferral = new GrammarAction( "Stores a referral" )
+    private GrammarAction<GracefulDisconnectContainer> storeReferral = 
+        new GrammarAction<GracefulDisconnectContainer>( "Stores a referral" )
     {
-        public void action( Asn1Container container ) throws DecoderException
+        public void action( GracefulDisconnectContainer container ) throws DecoderException
         {
-            GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
-            Value value = gracefulDisconnectContainer.getCurrentTLV().getValue();
+            Value value = container.getCurrentTLV().getValue();
 
             try
             {
                 LdapURL url = new LdapURL( value.getData() );
-                gracefulDisconnectContainer.getGracefulDisconnect().addReplicatedContexts( url );
-                gracefulDisconnectContainer.setGrammarEndAllowed( true );
+                container.getGracefulDisconnect().addReplicatedContexts( url );
+                container.setGrammarEndAllowed( true );
                 
                 if ( IS_DEBUG )
                 {
@@ -135,12 +133,12 @@
     /**
      * The action used to store a Time Offline.
      */
-    private GrammarAction storeTimeOffline = new GrammarAction( "Set Graceful Disconnect time offline" )
+    private GrammarAction<GracefulDisconnectContainer> storeTimeOffline = 
+        new GrammarAction<GracefulDisconnectContainer>( "Set Graceful Disconnect time offline" )
     {
-        public void action( Asn1Container container ) throws DecoderException
+        public void action( GracefulDisconnectContainer container ) throws DecoderException
         {
-            GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
-            Value value = gracefulDisconnectContainer.getCurrentTLV().getValue();
+            Value value = container.getCurrentTLV().getValue();
 
             try
             {
@@ -151,8 +149,8 @@
                     LOG.debug( "Time Offline = " + timeOffline );
                 }
 
-                gracefulDisconnectContainer.getGracefulDisconnect().setTimeOffline( timeOffline );
-                gracefulDisconnectContainer.setGrammarEndAllowed( true );
+                container.getGracefulDisconnect().setTimeOffline( timeOffline );
+                container.setGrammarEndAllowed( true );
             }
             catch ( IntegerDecoderException e )
             {
@@ -163,9 +161,11 @@
         }
     };
 
+    
     /**
      * Creates a new GracefulDisconnectGrammar object.
      */
+    @SuppressWarnings("unchecked")
     private GracefulDisconnectGrammar()
     {
         setName( GracefulDisconnectGrammar.class.getName() );
@@ -181,18 +181,16 @@
          * Creates the GracefulDisconnect object
          */
         super.transitions[GracefulDisconnectStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
-            new GrammarTransition( GracefulDisconnectStatesEnum.START_STATE,
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.START_STATE,
                                     GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE, 
                                     UniversalTag.SEQUENCE.getValue(),
-                new GrammarAction(
-                "Init Graceful Disconnect" )
+                new GrammarAction<GracefulDisconnectContainer>( "Init Graceful Disconnect" )
             {
-                public void action( Asn1Container container )
+                public void action( GracefulDisconnectContainer container )
                 {
-                    GracefulDisconnectContainer gracefulDisconnectContainer = ( GracefulDisconnectContainer ) container;
                     GracefulDisconnect gracefulDisconnect = new GracefulDisconnect();
-                    gracefulDisconnectContainer.setGracefulDisconnect( gracefulDisconnect );
-                    gracefulDisconnectContainer.setGrammarEndAllowed( true );
+                    container.setGracefulDisconnect( gracefulDisconnect );
+                    container.setGrammarEndAllowed( true );
                 }
             } );
 
@@ -206,10 +204,10 @@
          * Set the time offline value into the GracefulDisconnect object.    
          */
         super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] = 
-            new GrammarTransition( GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
-                                    GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE, 
-                                    UniversalTag.INTEGER.getValue(), 
-                storeTimeOffline );
+            new GrammarTransition<GracefulDisconnectContainer>( 
+                GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
+                GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE, 
+                UniversalTag.INTEGER.getValue(), storeTimeOffline );
         
         /**
          * Transition from graceful disconnect to delay
@@ -223,9 +221,10 @@
          */
         super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE.ordinal()]
                          [GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] = 
-            new GrammarTransition( GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
-                                    GracefulDisconnectStatesEnum.DELAY_STATE, 
-                                    GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG, 
+            new GrammarTransition<GracefulDisconnectContainer>( 
+                GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
+                GracefulDisconnectStatesEnum.DELAY_STATE, 
+                GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG, 
                 storeDelay );
         
         /**
@@ -240,9 +239,9 @@
          * Get some replicated contexts. Nothing to do    
          */
         super.transitions[GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
-            new GrammarTransition( GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
-                                    GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
-                                    UniversalTag.SEQUENCE.getValue(), null );
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.GRACEFUL_DISCONNECT_SEQUENCE_STATE,
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
         
         /**
          * Transition from time offline to delay
@@ -255,9 +254,9 @@
          * Set the delay value into the GracefulDisconnect object.    
          */
         super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] = 
-            new GrammarTransition( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
-                                    GracefulDisconnectStatesEnum.DELAY_STATE, 
-                                    GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG,
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
+                GracefulDisconnectStatesEnum.DELAY_STATE, 
+                GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG,
                 storeDelay );
 
         /**
@@ -272,9 +271,9 @@
          * Get some replicated contexts. Nothing to do    
          */
         super.transitions[GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
-            new GrammarTransition( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
-                                    GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
-                                    UniversalTag.SEQUENCE.getValue(), null );
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.TIME_OFFLINE_STATE,
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
+                UniversalTag.SEQUENCE.getValue(), null );
         
         /**
          * Transition from delay to replicated contexts
@@ -288,9 +287,9 @@
          * Get some replicated contexts. Nothing to do    
          */
         super.transitions[GracefulDisconnectStatesEnum.DELAY_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
-            new GrammarTransition( GracefulDisconnectStatesEnum.DELAY_STATE,
-                                    GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE, 
-                                    UniversalTag.SEQUENCE.getValue(), null );
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.DELAY_STATE,
+                GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE, 
+                UniversalTag.SEQUENCE.getValue(), null );
         
         /**
          * Transition from replicated contexts to referral
@@ -304,9 +303,9 @@
          * Stores the referral
          */
         super.transitions[GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
-            new GrammarTransition( GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
-                                    GracefulDisconnectStatesEnum.REFERRAL_STATE, 
-                                    UniversalTag.OCTET_STRING.getValue(),
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.REPLICATED_CONTEXTS_STATE,
+                GracefulDisconnectStatesEnum.REFERRAL_STATE, 
+                UniversalTag.OCTET_STRING.getValue(),
                 storeReferral );
 
         /**
@@ -321,9 +320,9 @@
          * Stores the referral
          */
         super.transitions[GracefulDisconnectStatesEnum.REFERRAL_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
-            new GrammarTransition( GracefulDisconnectStatesEnum.REFERRAL_STATE,
-                                    GracefulDisconnectStatesEnum.REFERRAL_STATE, 
-                                    UniversalTag.OCTET_STRING.getValue(),
+            new GrammarTransition<GracefulDisconnectContainer>( GracefulDisconnectStatesEnum.REFERRAL_STATE,
+                GracefulDisconnectStatesEnum.REFERRAL_STATE, 
+                UniversalTag.OCTET_STRING.getValue(),
                 storeReferral );
 
     }
@@ -334,7 +333,7 @@
      * 
      * @return An instance on this grammar
      */
-    public static Grammar getInstance()
+    public static GracefulDisconnectGrammar getInstance()
     {
         return instance;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectStatesEnum.java
similarity index 92%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectStatesEnum.java
index 7a981a3..6867e97 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectStatesEnum.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectStatesEnum.java
@@ -80,14 +80,9 @@
      * @param grammar The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<GracefulDisconnectContainer> grammar )
     {
-        if ( grammar instanceof GracefulDisconnectGrammar )
-        {
-            return "GRACEFUL_DISCONNECT_GRAMMAR";
-        }
-
-        return "UNKNOWN GRAMMAR";
+        return "GRACEFUL_DISCONNECT_GRAMMAR";
     }
 
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdown.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdown.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdown.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdown.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownDecoder.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownDecoder.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownDecoder.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownDecoder.java
diff --git a/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownFactory.java
new file mode 100644
index 0000000..c98db60
--- /dev/null
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownFactory.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.shared.ldap.extras.extended.ads_impl;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
+import org.apache.directory.shared.ldap.extras.extended.GracefulShutdownRequest;
+import org.apache.directory.shared.ldap.extras.extended.GracefulShutdownResponse;
+
+
+/**
+ * An {@link ExtendedRequestFactory} for creating cancel extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class GracefulShutdownFactory 
+    implements ExtendedRequestFactory<GracefulShutdownRequest, GracefulShutdownResponse>
+{
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return GracefulShutdownRequest.EXTENSION_OID;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public GracefulShutdownRequest newRequest()
+    {
+        return new GracefulShutdownRequest();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public GracefulShutdownResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        GracefulShutdownResponse response = new GracefulShutdownResponse();
+        response.setResponseValue( encodedValue );
+        return response;
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownGrammar.java
similarity index 77%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownGrammar.java
index 0df64d3..eb53ff5 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownGrammar.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownGrammar.java
@@ -21,9 +21,7 @@
 
 
 import org.apache.directory.shared.asn1.DecoderException;
-import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
-import org.apache.directory.shared.asn1.ber.grammar.Grammar;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
 import org.apache.directory.shared.asn1.ber.tlv.IntegerDecoderException;
@@ -50,7 +48,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class GracefulShutdownGrammar extends AbstractGrammar
+public final class GracefulShutdownGrammar extends AbstractGrammar<GracefulShutdownContainer>
 {
     /** The logger */
     static final Logger LOG = LoggerFactory.getLogger( GracefulShutdownGrammar.class );
@@ -59,12 +57,13 @@
     static final boolean IS_DEBUG = LOG.isDebugEnabled();
 
     /** The instance of grammar. GracefulShutdownGrammar is a singleton */
-    private static Grammar instance = new GracefulShutdownGrammar();
+    private static GracefulShutdownGrammar instance = new GracefulShutdownGrammar();
 
 
     /**
      * Creates a new GracefulShutdownGrammar object.
      */
+    @SuppressWarnings("unchecked")
     private GracefulShutdownGrammar()
     {
         setName( GracefulShutdownGrammar.class.getName() );
@@ -81,17 +80,16 @@
          * Creates the GracefulShutdown object
          */
         super.transitions[GracefulShutdownStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
-            new GrammarTransition( GracefulShutdownStatesEnum.START_STATE, 
+            new GrammarTransition<GracefulShutdownContainer>( GracefulShutdownStatesEnum.START_STATE, 
                 GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE, 
                 UniversalTag.SEQUENCE.getValue(),
-                new GrammarAction( "Init GracefulShutdown" )
+                new GrammarAction<GracefulShutdownContainer>( "Init GracefulShutdown" )
             {
-                public void action( Asn1Container container )
+                public void action( GracefulShutdownContainer container )
                 {
-                    GracefulShutdownContainer gracefulShutdownContainer = ( GracefulShutdownContainer ) container;
                     GracefulShutdown gracefulShutdown = new GracefulShutdown();
-                    gracefulShutdownContainer.setGracefulShutdown( gracefulShutdown );
-                    gracefulShutdownContainer.setGrammarEndAllowed( true );
+                    container.setGracefulShutdown( gracefulShutdown );
+                    container.setGrammarEndAllowed( true );
                 }
             } );
 
@@ -106,15 +104,14 @@
          * object.
          */
         super.transitions[GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] = 
-            new GrammarTransition( GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE, 
+            new GrammarTransition<GracefulShutdownContainer>( GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE, 
                                     GracefulShutdownStatesEnum.TIME_OFFLINE_STATE, 
                                     UniversalTag.INTEGER.getValue(), 
-                new GrammarAction( "Set Graceful Shutdown time offline" )
+                new GrammarAction<GracefulShutdownContainer>( "Set Graceful Shutdown time offline" )
             {
-                public void action( Asn1Container container ) throws DecoderException
+                public void action( GracefulShutdownContainer container ) throws DecoderException
                 {
-                    GracefulShutdownContainer gracefulShutdownContainer = ( GracefulShutdownContainer ) container;
-                    Value value = gracefulShutdownContainer.getCurrentTLV().getValue();
+                    Value value = container.getCurrentTLV().getValue();
 
                     try
                     {
@@ -125,8 +122,8 @@
                             LOG.debug( "Time Offline = " + timeOffline );
                         }
 
-                        gracefulShutdownContainer.getGracefulShutdown().setTimeOffline( timeOffline );
-                        gracefulShutdownContainer.setGrammarEndAllowed( true );
+                        container.getGracefulShutdown().setTimeOffline( timeOffline );
+                        container.setGrammarEndAllowed( true );
                     }
                     catch ( IntegerDecoderException e )
                     {
@@ -148,16 +145,15 @@
          * object.
          */
         super.transitions[GracefulShutdownStatesEnum.TIME_OFFLINE_STATE.ordinal()][GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] = 
-            new GrammarTransition( GracefulShutdownStatesEnum.TIME_OFFLINE_STATE, 
+            new GrammarTransition<GracefulShutdownContainer>( GracefulShutdownStatesEnum.TIME_OFFLINE_STATE, 
                                     GracefulShutdownStatesEnum.DELAY_STATE, 
                                     GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG, 
 
-                new GrammarAction( "Set Graceful Shutdown Delay" )
+                new GrammarAction<GracefulShutdownContainer>( "Set Graceful Shutdown Delay" )
             {
-                public void action( Asn1Container container ) throws DecoderException
+                public void action( GracefulShutdownContainer container ) throws DecoderException
                 {
-                    GracefulShutdownContainer gracefulShutdownContainer = ( GracefulShutdownContainer ) container;
-                    Value value = gracefulShutdownContainer.getCurrentTLV().getValue();
+                    Value value = container.getCurrentTLV().getValue();
 
                     try
                     {
@@ -168,8 +164,8 @@
                             LOG.debug( "Delay = " + delay );
                         }
 
-                        gracefulShutdownContainer.getGracefulShutdown().setDelay( delay );
-                        gracefulShutdownContainer.setGrammarEndAllowed( true );
+                        container.getGracefulShutdown().setDelay( delay );
+                        container.setGrammarEndAllowed( true );
                     }
                     catch ( IntegerDecoderException e )
                     {
@@ -192,13 +188,13 @@
          */
         super.transitions[GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE.ordinal()]
                          [GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG] = 
-            new GrammarTransition( GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE, 
+            new GrammarTransition<GracefulShutdownContainer>( GracefulShutdownStatesEnum.GRACEFUL_SHUTDOWN_SEQUENCE_STATE, 
                                     GracefulShutdownStatesEnum.DELAY_STATE, 
                                     GracefulActionConstants.GRACEFUL_ACTION_DELAY_TAG, 
 
-                new GrammarAction( "Set Graceful Shutdown Delay" )
+                new GrammarAction<GracefulShutdownContainer>( "Set Graceful Shutdown Delay" )
             {
-                public void action( Asn1Container container ) throws DecoderException
+                public void action( GracefulShutdownContainer container ) throws DecoderException
                 {
                     GracefulShutdownContainer gracefulShutdownContainer = ( GracefulShutdownContainer ) container;
                     Value value = gracefulShutdownContainer.getCurrentTLV().getValue();
@@ -231,7 +227,7 @@
      * 
      * @return An instance on this grammar
      */
-    public static Grammar getInstance()
+    public static GracefulShutdownGrammar getInstance()
     {
         return instance;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownStatesEnum.java
similarity index 92%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownStatesEnum.java
index aa9fe72..5fc0734 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownStatesEnum.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownStatesEnum.java
@@ -75,14 +75,9 @@
      * @param grammar The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<GracefulShutdownContainer> grammar )
     {
-        if ( grammar instanceof GracefulShutdownGrammar )
-        {
-            return "GRACEFUL_SHUTDOWN_GRAMMAR";
-        }
-
-        return "UNKNOWN GRAMMAR";
+        return "GRACEFUL_SHUTDOWN_GRAMMAR";
     }
 
 
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedure.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedure.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedure.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedure.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureContainer.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureContainer.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureContainer.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureContainer.java
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureDecoder.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureDecoder.java
similarity index 100%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureDecoder.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureDecoder.java
diff --git a/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureFactory.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureFactory.java
new file mode 100644
index 0000000..a5b9074
--- /dev/null
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureFactory.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.shared.ldap.extras.extended.ads_impl;
+
+
+import org.apache.directory.shared.asn1.DecoderException;
+import org.apache.directory.shared.ldap.codec.api.ExtendedRequestFactory;
+import org.apache.directory.shared.ldap.extras.extended.StoredProcedureRequest;
+import org.apache.directory.shared.ldap.extras.extended.StoredProcedureResponse;
+
+
+/**
+ * An {@link ExtendedRequestFactory} for creating cancel extended request response 
+ * pairs.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoredProcedureFactory implements ExtendedRequestFactory<StoredProcedureRequest, StoredProcedureResponse>
+{
+    /**
+     * {@inheritDoc}
+     */
+    public String getOid()
+    {
+        return StoredProcedureRequest.EXTENSION_OID;
+    }
+
+    
+    /**
+     * {@inheritDoc}
+     */
+    public StoredProcedureRequest newRequest()
+    {
+        return new StoredProcedureRequest();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public StoredProcedureResponse newResponse( byte[] encodedValue ) throws DecoderException
+    {
+        StoredProcedureResponse response = new StoredProcedureResponse();
+        response.setResponseValue( encodedValue );
+        return response;
+    }
+}
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureGrammar.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureGrammar.java
similarity index 82%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureGrammar.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureGrammar.java
index dbd8c64..5c1e76b 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureGrammar.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureGrammar.java
@@ -22,9 +22,7 @@
 
 
 import org.apache.directory.shared.asn1.DecoderException;
-import org.apache.directory.shared.asn1.ber.Asn1Container;
 import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
-import org.apache.directory.shared.asn1.ber.grammar.Grammar;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
 import org.apache.directory.shared.asn1.ber.tlv.TLV;
@@ -41,7 +39,7 @@
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class StoredProcedureGrammar extends AbstractGrammar
+public final class StoredProcedureGrammar extends AbstractGrammar<StoredProcedureContainer>
 {
     //~ Static fields/initializers -----------------------------------------------------------------
 
@@ -50,7 +48,7 @@
     static final Logger LOG = LoggerFactory.getLogger( StoredProcedureGrammar.class );
 
     /** The instance of grammar. StoredProcedureGrammar is a singleton. */
-    private static Grammar instance = new StoredProcedureGrammar();
+    private static StoredProcedureGrammar instance = new StoredProcedureGrammar();
 
 
     //~ Constructors -------------------------------------------------------------------------------
@@ -58,6 +56,7 @@
     /**
      * Creates a new StoredProcedureGrammar object.
      */
+    @SuppressWarnings("unchecked")
     private StoredProcedureGrammar()
     {
         setName( StoredProcedureGrammar.class.getName() );
@@ -72,7 +71,7 @@
         //   ...
         // Nothing to do.
         super.transitions[StoredProcedureStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
-            new GrammarTransition( StoredProcedureStatesEnum.START_STATE, 
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.START_STATE, 
                                     StoredProcedureStatesEnum.STORED_PROCEDURE_STATE, 
                                     UniversalTag.SEQUENCE.getValue(), 
                                     null );
@@ -82,17 +81,14 @@
         //
         // Creates the storeProcedure and stores the language
         super.transitions[StoredProcedureStatesEnum.STORED_PROCEDURE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
-            new GrammarTransition( StoredProcedureStatesEnum.STORED_PROCEDURE_STATE, 
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.STORED_PROCEDURE_STATE, 
                                     StoredProcedureStatesEnum.LANGUAGE_STATE, 
                                     UniversalTag.OCTET_STRING.getValue(),
-                new GrammarAction( "Stores the language" )
+                new GrammarAction<StoredProcedureContainer>( "Stores the language" )
             {
-                public void action( Asn1Container container ) throws DecoderException
+                public void action( StoredProcedureContainer container ) throws DecoderException
                 {
-
-                    StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
-
-                    TLV tlv = storedProcedureContainer.getCurrentTLV();
+                    TLV tlv = container.getCurrentTLV();
 
                     StoredProcedure storedProcedure = null;
 
@@ -116,7 +112,7 @@
 
                         storedProcedure = new StoredProcedure();
                         storedProcedure.setLanguage( language );
-                        storedProcedureContainer.setStoredProcedure( storedProcedure );
+                        container.setStoredProcedure( storedProcedure );
                     }
                 }
             } );
@@ -125,20 +121,16 @@
         //    ...
         // Stores the procedure.
         super.transitions[StoredProcedureStatesEnum.LANGUAGE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
-            new GrammarTransition( StoredProcedureStatesEnum.LANGUAGE_STATE, 
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.LANGUAGE_STATE, 
                                     StoredProcedureStatesEnum.PROCEDURE_STATE, 
                                     UniversalTag.OCTET_STRING.getValue(),
-                new GrammarAction(
-                "Stores the procedure" )
+                new GrammarAction<StoredProcedureContainer>( "Stores the procedure" )
             {
-                public void action( Asn1Container container ) throws DecoderException
+                public void action( StoredProcedureContainer container ) throws DecoderException
                 {
+                    TLV tlv = container.getCurrentTLV();
 
-                    StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
-
-                    TLV tlv = storedProcedureContainer.getCurrentTLV();
-
-                    StoredProcedure storedProcedure = storedProcedureContainer.getStoredProcedure();
+                    StoredProcedure storedProcedure = container.getStoredProcedure();
 
                     // Store the value.
                     if ( tlv.getLength() == 0 )
@@ -167,13 +159,12 @@
         // 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( StoredProcedureStatesEnum.PROCEDURE_STATE, 
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PROCEDURE_STATE, 
                                     StoredProcedureStatesEnum.PARAMETERS_STATE, 
                                     UniversalTag.SEQUENCE.getValue(), 
-            new GrammarAction(
-                "Stores the parameters" )
+            new GrammarAction<StoredProcedureContainer>( "Stores the parameters" )
             {
-                public void action( Asn1Container container ) throws DecoderException
+                public void action( StoredProcedureContainer container ) throws DecoderException
                 {
                     StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
                     storedProcedureContainer.setGrammarEndAllowed( true );
@@ -184,7 +175,7 @@
         //    ...
         // Nothing to do. 
         super.transitions[StoredProcedureStatesEnum.PARAMETERS_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
-            new GrammarTransition( StoredProcedureStatesEnum.PARAMETERS_STATE, 
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PARAMETERS_STATE, 
                                     StoredProcedureStatesEnum.PARAMETER_STATE, 
                                     UniversalTag.SEQUENCE.getValue(), 
                                     null );
@@ -195,17 +186,15 @@
         //
         // We can create a parameter, and store its type
         super.transitions[StoredProcedureStatesEnum.PARAMETER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
-            new GrammarTransition( StoredProcedureStatesEnum.PARAMETER_STATE, 
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PARAMETER_STATE, 
                                     StoredProcedureStatesEnum.PARAMETER_TYPE_STATE, 
                                     UniversalTag.OCTET_STRING.getValue(),
-                new GrammarAction( "Store parameter type" )
+                new GrammarAction<StoredProcedureContainer>( "Store parameter type" )
             {
-                public void action( Asn1Container container ) throws DecoderException
+                public void action( StoredProcedureContainer container ) throws DecoderException
                 {
-                    StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
-
-                    TLV tlv = storedProcedureContainer.getCurrentTLV();
-                    StoredProcedure storedProcedure = storedProcedureContainer.getStoredProcedure();
+                    TLV tlv = container.getCurrentTLV();
+                    StoredProcedure storedProcedure = container.getStoredProcedure();
 
                     // Store the value.
                     if ( tlv.getLength() == 0 )
@@ -241,12 +230,12 @@
         // }
         // Store the parameter value
         super.transitions[StoredProcedureStatesEnum.PARAMETER_TYPE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
-            new GrammarTransition( StoredProcedureStatesEnum.PARAMETER_TYPE_STATE, 
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PARAMETER_TYPE_STATE, 
                                     StoredProcedureStatesEnum.PARAMETER_VALUE_STATE, 
                                     UniversalTag.OCTET_STRING.getValue(),
-                new GrammarAction( "Store parameter value" )
+                new GrammarAction<StoredProcedureContainer>( "Store parameter value" )
             {
-                public void action( Asn1Container container ) throws DecoderException
+                public void action( StoredProcedureContainer container ) throws DecoderException
                 {
                     StoredProcedureContainer storedProcedureContainer = ( StoredProcedureContainer ) container;
 
@@ -295,7 +284,7 @@
         // 
         // Loop on next parameter
         super.transitions[StoredProcedureStatesEnum.PARAMETER_VALUE_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
-            new GrammarTransition( StoredProcedureStatesEnum.PARAMETER_VALUE_STATE, 
+            new GrammarTransition<StoredProcedureContainer>( StoredProcedureStatesEnum.PARAMETER_VALUE_STATE, 
                                     StoredProcedureStatesEnum.PARAMETER_STATE, 
                                     UniversalTag.SEQUENCE.getValue(),
                                     null );
@@ -309,7 +298,7 @@
      *
      * @return An instance on the StoredProcedure Grammar
      */
-    public static Grammar getInstance()
+    public static StoredProcedureGrammar getInstance()
     {
         return instance;
     }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureStatesEnum.java b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureStatesEnum.java
similarity index 92%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureStatesEnum.java
rename to ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureStatesEnum.java
index 5f2226d..eea4842 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureStatesEnum.java
+++ b/ldap-extras/codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureStatesEnum.java
@@ -90,16 +90,9 @@
      * @param grammar The grammar class
      * @return The grammar name
      */
-    public String getGrammarName( Grammar grammar )
+    public String getGrammarName( Grammar<StoredProcedureContainer> grammar )
     {
-        if ( grammar instanceof StoredProcedureGrammar )
-        {
-            return "STORED_PROCEDURE_GRAMMAR";
-        }
-        else
-        {
-            return "UNKNOWN GRAMMAR";
-        }
+        return "STORED_PROCEDURE_GRAMMAR";
     }
 
 
diff --git a/ldap/src/site/site.xml b/ldap-extras/codec/src/site/site.xml
similarity index 100%
copy from ldap/src/site/site.xml
copy to ldap-extras/codec/src/site/site.xml
diff --git a/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/codec/osgi/AbstractCodecServiceTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/codec/osgi/AbstractCodecServiceTest.java
new file mode 100644
index 0000000..8f20edd
--- /dev/null
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/codec/osgi/AbstractCodecServiceTest.java
@@ -0,0 +1,63 @@
+package org.apache.directory.shared.ldap.codec.osgi;
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT 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.shared.ldap.codec.LdapEncoder;
+import org.apache.directory.shared.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/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTest.java
similarity index 95%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTest.java
index eb95966..3f569b6 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/ppolicy_impl/PasswordPolicyTest.java
@@ -27,10 +27,8 @@
 
 import java.nio.ByteBuffer;
 
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.extras.controls.PasswordPolicy;
-import org.apache.directory.shared.ldap.extras.controls.ppolicy_impl.PasswordPolicyDecorator;
 import org.apache.directory.shared.util.Strings;
 import org.junit.Test;
 
@@ -40,10 +38,8 @@
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class PasswordPolicyTest
+public class PasswordPolicyTest extends AbstractCodecServiceTest
 {
-    LdapCodecService codec = new DefaultLdapCodecService();
-    
     @Test
     public void testDecodeRespWithExpiryWarningAndError() throws Exception
     {
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueControlTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueControlTest.java
similarity index 93%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueControlTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueControlTest.java
index 4a27431..a9f6e0e 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueControlTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncDoneValueControlTest.java
@@ -28,17 +28,16 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.EncoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.extras.controls.SyncDoneValue;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncDoneValueDecorator;
 import org.apache.directory.shared.util.Strings;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
 
 /**
  * 
@@ -48,11 +47,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SyncDoneValueControlTest
+public class SyncDoneValueControlTest extends AbstractCodecServiceTest
 {
-    private LdapCodecService codec = new DefaultLdapCodecService();
-
-    
     @Test
     public void testSyncDoneValueControl() throws Exception
     {
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueControlTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueControlTest.java
similarity index 99%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueControlTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueControlTest.java
index 612d4fc..5e5457d 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueControlTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncInfoValueControlTest.java
@@ -19,6 +19,7 @@
  */
 package org.apache.directory.shared.ldap.extras.controls.syncrepl_impl;
 
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -26,19 +27,19 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.extras.controls.SyncInfoValue;
 import org.apache.directory.shared.ldap.extras.controls.SynchronizationInfoEnum;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncInfoValueDecorator;
 import org.apache.directory.shared.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
  * 
@@ -46,13 +47,12 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SyncInfoValueControlTest
+public class SyncInfoValueControlTest extends AbstractCodecServiceTest
 {
-    private LdapCodecService codec = new DefaultLdapCodecService();
-
     //--------------------------------------------------------------------------------
     // NewCookie choice tests
     //--------------------------------------------------------------------------------
+
     /**
      * Test the decoding of a SyncInfoValue control, newCookie choice
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnControlTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnControlTest.java
similarity index 94%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnControlTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnControlTest.java
index 2a22249..01af275 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnControlTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncModifyDnControlTest.java
@@ -27,18 +27,17 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.extras.controls.SyncModifyDn;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncModifyDnDecorator;
 import org.apache.directory.shared.util.Strings;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
 
 /**
  * TODO SyncModifyDnControlTest.
@@ -47,11 +46,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SyncModifyDnControlTest
+public class SyncModifyDnControlTest extends AbstractCodecServiceTest
 {
-    private LdapCodecService codec = new DefaultLdapCodecService();
-    
-    
     @Test
     public void testDecodeSyncModifyDnControlWithMoveOperation() throws Exception
     {
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueControlTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueControlTest.java
similarity index 97%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueControlTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueControlTest.java
index 219d33c..c0e228b 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueControlTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncRequestValueControlTest.java
@@ -27,19 +27,18 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.extras.controls.SyncRequestValue;
 import org.apache.directory.shared.ldap.extras.controls.SynchronizationModeEnum;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncRequestValueDecorator;
 import org.apache.directory.shared.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
@@ -48,11 +47,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SyncRequestValueControlTest
+public class SyncRequestValueControlTest extends AbstractCodecServiceTest
 {
-    private LdapCodecService codec = new DefaultLdapCodecService();
-    
-    
     /**
      * Test the decoding of a SyncRequestValue control with a refreshOnly mode
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueControlTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueControlTest.java
similarity index 96%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueControlTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueControlTest.java
index a019064..747e73c 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueControlTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/controls/syncrepl_impl/SyncStateValueControlTest.java
@@ -26,19 +26,18 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
-import org.apache.directory.shared.ldap.codec.api.DefaultLdapCodecService;
-import org.apache.directory.shared.ldap.codec.api.LdapCodecService;
+import org.apache.directory.shared.ldap.codec.osgi.AbstractCodecServiceTest;
 import org.apache.directory.shared.ldap.extras.controls.SyncStateTypeEnum;
 import org.apache.directory.shared.ldap.extras.controls.SyncStateValue;
-import org.apache.directory.shared.ldap.extras.controls.syncrepl_impl.SyncStateValueDecorator;
 import org.apache.directory.shared.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
@@ -47,10 +46,8 @@
  */
 @RunWith(ConcurrentJunitRunner.class)
 @Concurrency()
-public class SyncStateValueControlTest
+public class SyncStateValueControlTest extends AbstractCodecServiceTest
 {
-    private LdapCodecService codec = new DefaultLdapCodecService();
-    
     /**
      * Test the decoding of a SyncStateValue control with a refreshOnly mode
      */
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelRequestTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelRequestTest.java
similarity index 99%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelRequestTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelRequestTest.java
index c8e9a49..470702a 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelRequestTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CancelRequestTest.java
@@ -27,8 +27,6 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
@@ -40,6 +38,9 @@
 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
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationRequestTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationRequestTest.java
similarity index 99%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationRequestTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationRequestTest.java
index 5d8acbf..bdace32 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationRequestTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/CertGenerationRequestTest.java
@@ -26,8 +26,6 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.EncoderException;
@@ -37,6 +35,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
 
 /**
  * 
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectTest.java
similarity index 96%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectTest.java
index add8f15..4197ff3 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulDisconnectTest.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.ldap.extras.extended.ads_impl;
 
@@ -26,22 +26,20 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
-import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.EncoderException;
-import org.apache.directory.shared.ldap.extras.extended.ads_impl.GracefulDisconnect;
-import org.apache.directory.shared.ldap.extras.extended.ads_impl.GracefulDisconnectContainer;
-import org.apache.directory.shared.ldap.extras.extended.ads_impl.GracefulDisconnectDecoder;
+import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.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)
@@ -90,7 +88,7 @@
         assertEquals( 1, gracefulDisconnect.getDelay() );
         assertEquals( 2, gracefulDisconnect.getReplicatedContexts().size() );
         assertEquals( "ldap://directory.apache.org:80/", gracefulDisconnect.getReplicatedContexts().get( 0 ).toString() );
-        assertEquals( "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5c00%5c00%5c00%5c04)", gracefulDisconnect
+        assertEquals( "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5C00%5C00%5C00%5C04)", gracefulDisconnect
             .getReplicatedContexts().get( 1 ).toString() );
 
         // Check the length
@@ -111,7 +109,7 @@
             fail( ee.getMessage() );
         }
     }
-    
+
 
     /**
      * Test the decoding of a GracefulDisconnect with a timeOffline only
@@ -284,16 +282,16 @@
         Asn1Decoder decoder = new GracefulDisconnectDecoder();
         ByteBuffer stream = ByteBuffer.allocate( 0x6A );
         stream.put( new byte[]
-            { 
+            {
             0x30, 0x68,             // GracefulDisconnec ::= SEQUENCE {
               0x30, 0x66,           // replicatedContexts Referral OPTIONAL
-                0x04, 0x1F, 
+                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', 
+                  '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', ')'
             } );
 
@@ -317,7 +315,7 @@
         assertEquals( 0, gracefulDisconnect.getDelay() );
         assertEquals( 2, gracefulDisconnect.getReplicatedContexts().size() );
         assertEquals( "ldap://directory.apache.org:80/", gracefulDisconnect.getReplicatedContexts().get( 0 ).toString() );
-        assertEquals( "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5c00%5c00%5c00%5c04)", gracefulDisconnect
+        assertEquals( "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5C00%5C00%5C00%5C04)", gracefulDisconnect
             .getReplicatedContexts().get( 1 ).toString() );
 
         // Check the length
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownTest.java
similarity index 99%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownTest.java
index 499e89e..6401826 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/GracefulShutdownTest.java
@@ -26,8 +26,6 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.DecoderException;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
@@ -37,6 +35,9 @@
 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
diff --git a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureTest.java b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureTest.java
similarity index 99%
rename from ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureTest.java
rename to ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureTest.java
index e964178..58a9181 100644
--- a/ldap-codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureTest.java
+++ b/ldap-extras/codec/src/test/java/org/apache/directory/shared/ldap/extras/extended/ads_impl/StoredProcedureTest.java
@@ -26,8 +26,6 @@
 
 import java.nio.ByteBuffer;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.asn1.EncoderException;
 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
 import org.apache.directory.shared.asn1.ber.Asn1Container;
@@ -40,6 +38,9 @@
 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
diff --git a/ldap/src/test/resources/log4j.properties b/ldap-extras/codec/src/test/resources/log4j.properties
similarity index 100%
copy from ldap/src/test/resources/log4j.properties
copy to ldap-extras/codec/src/test/resources/log4j.properties
diff --git a/ldap-extras/pom.xml b/ldap-extras/pom.xml
new file mode 100644
index 0000000..8a80f41
--- /dev/null
+++ b/ldap-extras/pom.xml
@@ -0,0 +1,60 @@
+<?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.shared</groupId>
+    <artifactId>shared-parent</artifactId>
+    <version>1.0.0-M2-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>shared-ldap-extras-parent</artifactId>
+  <name>Apache Directory Shared LDAP Extras</name>
+  <inceptionYear>2003</inceptionYear>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>aci</module>
+    <module>codec</module>
+    <module>sp</module>
+    <module>trigger</module>
+    <module>util</module>
+  </modules>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/directory/shared/trunk/ldap-extras</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/directory/shared/trunk/ldap-extras</developerConnection>
+    <url>http://svn.apache.org/viewvc/directory/shared/trunk/ldap-extras</url>
+  </scm>
+
+</project>
diff --git a/ldap-extras/sp/pom.xml b/ldap-extras/sp/pom.xml
new file mode 100644
index 0000000..62816d4
--- /dev/null
+++ b/ldap-extras/sp/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.shared</groupId>
+    <artifactId>shared-ldap-extras-parent</artifactId>
+    <version>1.0.0-M2-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>shared-ldap-extras-sp</artifactId>
+  <name>Apache Directory Shared LDAP Extras Stored Procedures</name>
+  <packaging>bundle</packaging>
+  <description>Shared Extras LDAP 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>shared-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-model</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-codec-standalone</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-extras-codec</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-extras-util</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.shared.ldap.sp
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/ldap/src/checkstyle/suppressions.xml b/ldap-extras/sp/src/checkstyle/suppressions.xml
similarity index 100%
rename from ldap/src/checkstyle/suppressions.xml
rename to ldap-extras/sp/src/checkstyle/suppressions.xml
diff --git a/ldap/src/main/appended-resources/META-INF/LICENSE b/ldap-extras/sp/src/main/appended-resources/META-INF/LICENSE
similarity index 100%
rename from ldap/src/main/appended-resources/META-INF/LICENSE
rename to ldap-extras/sp/src/main/appended-resources/META-INF/LICENSE
diff --git a/ldap/src/main/appended-resources/META-INF/NOTICE b/ldap-extras/sp/src/main/appended-resources/META-INF/NOTICE
similarity index 100%
rename from ldap/src/main/appended-resources/META-INF/NOTICE
rename to ldap-extras/sp/src/main/appended-resources/META-INF/NOTICE
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/sp/JavaStoredProcUtils.java b/ldap-extras/sp/src/main/java/org/apache/directory/shared/ldap/sp/JavaStoredProcUtils.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/sp/JavaStoredProcUtils.java
rename to ldap-extras/sp/src/main/java/org/apache/directory/shared/ldap/sp/JavaStoredProcUtils.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/sp/LdapContextParameter.java b/ldap-extras/sp/src/main/java/org/apache/directory/shared/ldap/sp/LdapContextParameter.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/sp/LdapContextParameter.java
rename to ldap-extras/sp/src/main/java/org/apache/directory/shared/ldap/sp/LdapContextParameter.java
diff --git a/ldap/src/site/site.xml b/ldap-extras/sp/src/site/site.xml
similarity index 100%
rename from ldap/src/site/site.xml
rename to ldap-extras/sp/src/site/site.xml
diff --git a/ldap/src/test/resources/log4j.properties b/ldap-extras/sp/src/test/resources/log4j.properties
similarity index 100%
rename from ldap/src/test/resources/log4j.properties
rename to ldap-extras/sp/src/test/resources/log4j.properties
diff --git a/ldap-extras/trigger/pom.xml b/ldap-extras/trigger/pom.xml
new file mode 100644
index 0000000..936b189
--- /dev/null
+++ b/ldap-extras/trigger/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.shared</groupId>
+    <artifactId>shared-ldap-extras-parent</artifactId>
+    <version>1.0.0-M2-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>shared-ldap-extras-trigger</artifactId>
+  <name>Apache Directory Shared LDAP Extras Trigger</name>
+  <packaging>bundle</packaging>
+  <description>Shared Extra LDAP 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>shared-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-model</artifactId>
+    </dependency> 
+    
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>antlr-maven-plugin</artifactId>
+        <version>2.1</version>
+        <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.shared.ldap.trigger
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/ldap/src/checkstyle/suppressions.xml b/ldap-extras/trigger/src/checkstyle/suppressions.xml
similarity index 100%
copy from ldap/src/checkstyle/suppressions.xml
copy to ldap-extras/trigger/src/checkstyle/suppressions.xml
diff --git a/ldap/src/main/antlr/TriggerSpecification.g b/ldap-extras/trigger/src/main/antlr/TriggerSpecification.g
similarity index 100%
rename from ldap/src/main/antlr/TriggerSpecification.g
rename to ldap-extras/trigger/src/main/antlr/TriggerSpecification.g
diff --git a/ldap/src/main/appended-resources/META-INF/LICENSE b/ldap-extras/trigger/src/main/appended-resources/META-INF/LICENSE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/LICENSE
copy to ldap-extras/trigger/src/main/appended-resources/META-INF/LICENSE
diff --git a/ldap/src/main/appended-resources/META-INF/NOTICE b/ldap-extras/trigger/src/main/appended-resources/META-INF/NOTICE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/NOTICE
copy to ldap-extras/trigger/src/main/appended-resources/META-INF/NOTICE
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/ActionTime.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/ActionTime.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/ActionTime.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/ActionTime.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/LdapOperation.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/LdapOperation.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/LdapOperation.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/LdapOperation.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/ReusableAntlrTriggerSpecificationLexer.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/ReusableAntlrTriggerSpecificationLexer.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/ReusableAntlrTriggerSpecificationLexer.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/ReusableAntlrTriggerSpecificationLexer.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/ReusableAntlrTriggerSpecificationParser.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/ReusableAntlrTriggerSpecificationParser.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/ReusableAntlrTriggerSpecificationParser.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/ReusableAntlrTriggerSpecificationParser.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureLanguageSchemeOption.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureLanguageSchemeOption.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureLanguageSchemeOption.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureLanguageSchemeOption.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureOption.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureOption.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureOption.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureOption.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureParameter.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureParameter.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureParameter.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureParameter.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureSearchContextOption.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureSearchContextOption.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureSearchContextOption.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/StoredProcedureSearchContextOption.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerSpecification.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerSpecification.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerSpecification.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerSpecification.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerSpecificationParser.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerSpecificationParser.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerSpecificationParser.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerSpecificationParser.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerUtils.java b/ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerUtils.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerUtils.java
rename to ldap-extras/trigger/src/main/java/org/apache/directory/shared/ldap/trigger/TriggerUtils.java
diff --git a/ldap/src/site/site.xml b/ldap-extras/trigger/src/site/site.xml
similarity index 100%
copy from ldap/src/site/site.xml
copy to ldap-extras/trigger/src/site/site.xml
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/trigger/TriggerSpecificationParserTest.java b/ldap-extras/trigger/src/test/java/org/apache/directory/shared/ldap/trigger/TriggerSpecificationParserTest.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/trigger/TriggerSpecificationParserTest.java
rename to ldap-extras/trigger/src/test/java/org/apache/directory/shared/ldap/trigger/TriggerSpecificationParserTest.java
diff --git a/ldap/src/test/resources/log4j.properties b/ldap-extras/trigger/src/test/resources/log4j.properties
similarity index 100%
copy from ldap/src/test/resources/log4j.properties
copy to ldap-extras/trigger/src/test/resources/log4j.properties
diff --git a/ldap-extras/util/pom.xml b/ldap-extras/util/pom.xml
new file mode 100644
index 0000000..63cf8ad
--- /dev/null
+++ b/ldap-extras/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.shared</groupId>
+    <artifactId>shared-ldap-extras-parent</artifactId>
+    <version>1.0.0-M2-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>shared-ldap-extras-util</artifactId>
+  <name>Apache Directory Shared LDAP Extras Util</name>
+  <packaging>bundle</packaging>
+  <description>Shared LDAP 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>shared-util</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-asn1-api</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-i18n</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-model</artifactId>
+    </dependency> 
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>shared-ldap-codec-standalone</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.shared.ldap.util*
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/ldap/src/checkstyle/suppressions.xml b/ldap-extras/util/src/checkstyle/suppressions.xml
similarity index 100%
copy from ldap/src/checkstyle/suppressions.xml
copy to ldap-extras/util/src/checkstyle/suppressions.xml
diff --git a/ldap/src/main/appended-resources/META-INF/LICENSE b/ldap-extras/util/src/main/appended-resources/META-INF/LICENSE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/LICENSE
copy to ldap-extras/util/src/main/appended-resources/META-INF/LICENSE
diff --git a/ldap/src/main/appended-resources/META-INF/NOTICE b/ldap-extras/util/src/main/appended-resources/META-INF/NOTICE
similarity index 100%
copy from ldap/src/main/appended-resources/META-INF/NOTICE
copy to ldap-extras/util/src/main/appended-resources/META-INF/NOTICE
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/util/JndiUtils.java b/ldap-extras/util/src/main/java/org/apache/directory/shared/ldap/util/JndiUtils.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/util/JndiUtils.java
rename to ldap-extras/util/src/main/java/org/apache/directory/shared/ldap/util/JndiUtils.java
diff --git a/ldap/src/main/java/org/apache/directory/shared/ldap/util/tree/DnNode.java b/ldap-extras/util/src/main/java/org/apache/directory/shared/ldap/util/tree/DnNode.java
similarity index 100%
rename from ldap/src/main/java/org/apache/directory/shared/ldap/util/tree/DnNode.java
rename to ldap-extras/util/src/main/java/org/apache/directory/shared/ldap/util/tree/DnNode.java
diff --git a/ldap/src/site/site.xml b/ldap-extras/util/src/site/site.xml
similarity index 100%
copy from ldap/src/site/site.xml
copy to ldap-extras/util/src/site/site.xml
diff --git a/ldap/src/test/java/org/apache/directory/shared/ldap/util/tree/TestDnNode.java b/ldap-extras/util/src/test/java/org/apache/directory/shared/ldap/util/tree/TestDnNode.java
similarity index 100%
rename from ldap/src/test/java/org/apache/directory/shared/ldap/util/tree/TestDnNode.java
rename to ldap-extras/util/src/test/java/org/apache/directory/shared/ldap/util/tree/TestDnNode.java
diff --git a/ldap/src/test/resources/log4j.properties b/ldap-extras/util/src/test/resources/log4j.properties
similarity index 100%
copy from ldap/src/test/resources/log4j.properties
copy to ldap-extras/util/src/test/resources/log4j.properties
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/constants/SaslQoP.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/constants/SaslQoP.java
index 4cfa39f..e6113a6 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/constants/SaslQoP.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/constants/SaslQoP.java
@@ -21,32 +21,43 @@
 
 
 /**
- * Contains constants used for populating the SASL QoP 
- * in the RootDSE.
- * Final reference -> class shouldn't be extended
+ * This enums contains values for SASL QoP (Quality of Protection).
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public final class SaslQoP
+public enum SaslQoP
 {
-    /**
-     *  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 SaslQoP()
-    {
-    }
-
-    /** The supported QOP attribute */
-    public final static String ATTRIBUTE = "supportedQoP";
-
     /** Authentication only */
-    public final static String QOP_AUTH      = "auth" ;
+    AUTH("auth"),
 
     /** Authentication with integrity protection */
-    public final static String QOP_AUTH_INT  = "auth-int" ;
+    AUTH_INT("auth-int"),
 
     /** Authentication with integrity and privacy protection */
-    public final static String QOP_AUTH_CONF = "auth-conf" ;
+    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/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/constants/SaslSecurityStrength.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/constants/SaslSecurityStrength.java
new file mode 100644
index 0000000..15e24d6
--- /dev/null
+++ b/ldap-model/src/main/java/org/apache/directory/shared/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.shared.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/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/entry/DefaultEntry.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/entry/DefaultEntry.java
index 17aa162..f700ef4 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/entry/DefaultEntry.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/entry/DefaultEntry.java
@@ -35,13 +35,14 @@
 import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
 import org.apache.directory.shared.ldap.model.exception.LdapException;
 import org.apache.directory.shared.ldap.model.name.Dn;
+import org.apache.directory.shared.ldap.model.name.DnSerializer;
 import org.apache.directory.shared.ldap.model.name.Rdn;
 import org.apache.directory.shared.ldap.model.name.RdnSerializer;
-import org.apache.directory.shared.util.exception.NotImplementedException;
 import org.apache.directory.shared.ldap.model.schema.AttributeType;
 import org.apache.directory.shared.ldap.model.schema.SchemaManager;
 import org.apache.directory.shared.util.Strings;
 import org.apache.directory.shared.util.Unicode;
+import org.apache.directory.shared.util.exception.NotImplementedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -2485,12 +2486,12 @@
         if ( dn == null )
         {
             // Write an empty Dn
-            out.writeObject( Dn.EMPTY_DN );
+            DnSerializer.serialize( Dn.EMPTY_DN, out );
         }
         else
         {
             // Write the Dn
-            out.writeObject( dn );
+            DnSerializer.serialize( dn, out );
         }
 
         // Then the attributes.
@@ -2514,7 +2515,7 @@
     public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
     {
         // Read the Dn
-        dn = (Dn) in.readObject();
+        dn = DnSerializer.deserialize( in );
 
         // Read the number of attributes
         int nbAttributes = in.readInt();
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/filter/LdapURL.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/filter/LdapURL.java
index f0dc136..7d2611e 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/filter/LdapURL.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/filter/LdapURL.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.ldap.model.filter;
 
@@ -28,7 +28,6 @@
 import java.util.List;
 import java.util.Set;
 
-import org.apache.directory.shared.asn1.Hex;
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
 import org.apache.directory.shared.ldap.model.exception.LdapURLEncodingException;
@@ -295,7 +294,7 @@
 
     /**
      * 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
      */
@@ -321,7 +320,7 @@
 
     /**
      * Create a new LdapURL after having parsed it.
-     * 
+     *
      * @param bytes The byte buffer that contains the LDAPURL
      * @throws LdapURLEncodingException If the byte array does not comply with RFC 2255
      */
@@ -356,7 +355,7 @@
      * &lt;hostnumber&gt; ::= &lt;digits&gt; "." &lt;digits&gt; "."
      * &lt;digits&gt; "." &lt;digits&gt;
      * </p>
-     * 
+     *
      * @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
@@ -402,7 +401,7 @@
                 }
 
                 // Let's check the string we had before the dot.
-                if ( isHostNumber && nbDots < 4 )
+                if ( isHostNumber && ( nbDots < 4 ) )
                 {
 
                     // We had only digits. It may be an IP adress? Check it
@@ -503,7 +502,7 @@
      * &lt;digit&gt; ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
      * </p>
      * 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
@@ -542,7 +541,7 @@
      * <p>
      * &lt;hostport&gt; ::= &lt;host&gt; ':' &lt;port&gt;
      * </p>
-     * 
+     *
      * @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
@@ -587,7 +586,7 @@
      * 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
@@ -602,7 +601,7 @@
             throw new IllegalArgumentException( I18n.err( I18n.ERR_04411 ) );
         }
 
-        if ( charset == null || charset.length() == 0 )
+        if ( ( charset == null ) || ( charset.length() == 0 ) )
         {
             throw new IllegalArgumentException( I18n.err( I18n.ERR_04412 ) );
         }
@@ -622,7 +621,7 @@
      * 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.
@@ -636,7 +635,7 @@
 
     /**
      * 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.shared.ldap.model.exception.UrlDecoderException if encoding is not supported
@@ -664,7 +663,7 @@
      * 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
@@ -689,7 +688,7 @@
                     int u = Character.digit( ( char ) bytes[++i], 16 );
                     int l = Character.digit( ( char ) bytes[++i], 16 );
 
-                    if ( u == -1 || l == -1 )
+                    if ( ( u == -1 ) || ( l == -1 ) )
                     {
                         throw new UrlDecoderException( I18n.err( I18n.ERR_04414 ) );
                     }
@@ -714,7 +713,7 @@
     /**
      * 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)
@@ -736,7 +735,7 @@
     /**
      * 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
@@ -770,7 +769,7 @@
 
     /**
      * 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
@@ -878,7 +877,7 @@
 
     /**
      * 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
@@ -919,7 +918,7 @@
 
     /**
      * 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
@@ -999,12 +998,12 @@
 
 
     /**
-     * Parse extensions and critical extensions. 
-     * 
-     * The grammar is : 
-     * extensions ::= extension [ ',' extension ]* 
+     * 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
@@ -1125,7 +1124,7 @@
     /**
      * 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
@@ -1139,7 +1138,7 @@
      * 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].
@@ -1151,18 +1150,18 @@
      *
      *
      * 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
@@ -1296,7 +1295,7 @@
 
                     // percent encoding
                     byte[] bytes = Unicode.charToBytes(c);
-                    char[] hex = Hex.encodeHex( bytes );
+                    char[] hex = Strings.toHexString( bytes ).toCharArray();
                     for ( int j = 0; j < hex.length; j++ )
                     {
                         if ( j % 2 == 0 )
@@ -1317,10 +1316,11 @@
 
     /**
      * Get a string representation of a LdapURL.
-     * 
+     *
      * @return A LdapURL string
      * @see LdapURL#forceScopeRendering
      */
+    @Override
     public String toString()
     {
         StringBuffer sb = new StringBuffer();
@@ -1338,7 +1338,7 @@
         {
             sb.append( '/' ).append( urlEncode( dn.getName(), false ) );
 
-            if ( attributes.size() != 0 || forceScopeRendering
+            if ( ( attributes.size() != 0 ) || forceScopeRendering
                 || ( ( scope != SearchScope.OBJECT ) || ( filter != null ) || ( extensionList.size() != 0 ) ) )
             {
                 sb.append( '?' );
@@ -1468,10 +1468,10 @@
 
     /**
      * Gets the extension.
-     * 
+     *
      * @param type the extension type, case-insensitive
-     * 
-     * @return Returns the extension, null if this URL does not contain 
+     *
+     * @return Returns the extension, null if this URL does not contain
      *         such an extension.
      */
     public Extension getExtension( String type )
@@ -1489,10 +1489,10 @@
 
     /**
      * Gets the extension value.
-     * 
+     *
      * @param type the extension type, case-insensitive
-     * 
-     * @return Returns the extension value, null if this URL does not  
+     *
+     * @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 )
@@ -1538,7 +1538,7 @@
     /**
      * Returns the scope, one of {@link SearchScope#OBJECT},
      * {@link SearchScope#ONELEVEL} or {@link SearchScope#SUBTREE}.
-     * 
+     *
      * @return Returns the scope.
      */
     public SearchScope getScope()
@@ -1637,12 +1637,12 @@
 
     /**
      * 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 ) )
+        if ( ( ( scheme != null ) && LDAP_SCHEME.equals( scheme ) ) || LDAPS_SCHEME.equals( scheme ) )
         {
             this.scheme = scheme;
         }
@@ -1656,7 +1656,7 @@
 
     /**
      * Sets the host.
-     * 
+     *
      * @param host the new host
      */
     public void setHost( String host )
@@ -1667,12 +1667,12 @@
 
     /**
      * 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 )
+        if ( ( port < 1 ) || ( port > 65535 ) )
         {
             this.port = -1;
         }
@@ -1685,7 +1685,7 @@
 
     /**
      * Sets the dn.
-     * 
+     *
      * @param dn the new dn
      */
     public void setDn( Dn dn )
@@ -1696,7 +1696,7 @@
 
     /**
      * Sets the attributes, null removes all existing attributes.
-     * 
+     *
      * @param attributes the new attributes
      */
     public void setAttributes( List<String> attributes )
@@ -1716,7 +1716,7 @@
      * 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 )
@@ -1736,7 +1736,7 @@
      * 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 )
@@ -1754,7 +1754,7 @@
 
     /**
      * Sets the filter.
-     * 
+     *
      * @param filter the new filter
      */
     public void setFilter( String filter )
@@ -1764,10 +1764,10 @@
 
 
     /**
-     * If set to true forces the toString method to render the scope 
+     * 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 )
@@ -1777,10 +1777,10 @@
 
 
     /**
-     * If set to true forces the toString method to render the scope 
+     * 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.
-     * 
+     *
      * @return the forceScopeRendering
      */
     public boolean isForceScopeRendering()
@@ -1818,7 +1818,7 @@
 
         /**
          * Checks if is critical.
-         * 
+         *
          * @return true, if is critical
          */
         public boolean isCritical()
@@ -1829,7 +1829,7 @@
 
         /**
          * Sets the critical flag.
-         * 
+         *
          * @param critical the new critical flag
          */
         public void setCritical( boolean critical )
@@ -1840,7 +1840,7 @@
 
         /**
          * Gets the type.
-         * 
+         *
          * @return the type
          */
         public String getType()
@@ -1851,7 +1851,7 @@
 
         /**
          * Sets the type.
-         * 
+         *
          * @param type the new type
          */
         public void setType( String type )
@@ -1862,7 +1862,7 @@
 
         /**
          * Gets the value.
-         * 
+         *
          * @return the value
          */
         public String getValue()
@@ -1873,7 +1873,7 @@
 
         /**
          * Sets the value.
-         * 
+         *
          * @param value the new value
          */
         public void setValue( String value )
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/ldif/LdifRevertor.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/ldif/LdifRevertor.java
index 435533a..39e7304 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/ldif/LdifRevertor.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/ldif/LdifRevertor.java
@@ -285,7 +285,7 @@
 
         currentParent = modifiedDn;
         currentRdn = currentParent.getRdn();
-        currentParent = currentParent.remove( currentParent.size() - 1 );
+        currentParent = currentParent.getParent();
 
         newDn = newSuperiorDn;
         newDn = newDn.add( modifiedDn.getRdn() );
@@ -334,7 +334,7 @@
         {
             Dn oldSuperior = entry.getDn();
 
-            oldSuperior = oldSuperior.remove( oldSuperior.size() - 1 );
+            oldSuperior = oldSuperior.getParent();
             reverted.setNewSuperior( oldSuperior.getName() );
         }
 
@@ -399,7 +399,7 @@
         {
             Dn oldSuperior = newDn;
 
-            oldSuperior = oldSuperior.remove( oldSuperior.size() - 1 );
+            oldSuperior = oldSuperior.getParent();
             reverted.setNewSuperior( oldSuperior.getName() );
         }
 
@@ -465,7 +465,7 @@
         Rdn oldRdn = parentDn.getRdn();
 
         newDn = parentDn;
-        newDn = newDn.remove( newDn.size() - 1 );
+        newDn = newDn.getParent();
         newDn = newDn.add( newRdn );
 
         List<LdifEntry> entries = new ArrayList<LdifEntry>( 1 );
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AbstractMessage.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AbstractMessage.java
index e3a6ca0..3139656 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AbstractMessage.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AbstractMessage.java
@@ -264,9 +264,14 @@
      * 
      * @return A LdapMessage String
      */
-    public String toString()
+    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 )
         {
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AddRequestImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AddRequestImpl.java
index 60c6fee..ed3f6dc 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AddRequestImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AddRequestImpl.java
@@ -20,7 +20,11 @@
 package org.apache.directory.shared.ldap.model.message;
 
 
-import org.apache.directory.shared.ldap.model.entry.*;
+import org.apache.directory.shared.ldap.model.entry.DefaultEntry;
+import org.apache.directory.shared.ldap.model.entry.DefaultEntryAttribute;
+import org.apache.directory.shared.ldap.model.entry.Entry;
+import org.apache.directory.shared.ldap.model.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.model.entry.Value;
 import org.apache.directory.shared.ldap.model.exception.LdapException;
 import org.apache.directory.shared.ldap.model.name.Dn;
 
@@ -291,6 +295,6 @@
             sb.append( entry.toString() );
         }
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AddResponseImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AddResponseImpl.java
index 76cfa52..767afd5 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AddResponseImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/AddResponseImpl.java
@@ -62,6 +62,6 @@
         sb.append( "    Add Response\n" );
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/BindRequestImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/BindRequestImpl.java
index cd7fb22..8fd0478 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/BindRequestImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/BindRequestImpl.java
@@ -418,6 +418,7 @@
     public String toString()
     {
         StringBuffer sb = new StringBuffer();
+        
         sb.append( "    BindRequest\n" );
         sb.append( "        Version : '" ).append( isVersion3 ? "3" : "2" ).append( "'\n" );
 
@@ -451,8 +452,6 @@
         }
 
         // The controls if any
-        sb.append( super.toString() );
-
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/BindResponseImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/BindResponseImpl.java
index da7591f..acb8a13 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/BindResponseImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/BindResponseImpl.java
@@ -187,6 +187,6 @@
                 .append( "'\n" );
         }
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/CompareRequestImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/CompareRequestImpl.java
index 94352a4..7b51414 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/CompareRequestImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/CompareRequestImpl.java
@@ -328,6 +328,6 @@
         // The controls
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/CompareResponseImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/CompareResponseImpl.java
index 4a8fa28..a1c1193 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/CompareResponseImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/CompareResponseImpl.java
@@ -72,6 +72,6 @@
         sb.append( "    Compare Response\n" );
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/DeleteRequestImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/DeleteRequestImpl.java
index 6393b08..d389c43 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/DeleteRequestImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/DeleteRequestImpl.java
@@ -201,6 +201,6 @@
         sb.append( "        Entry : '" ).append( name.toString() ).append( "'\n" );
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/DeleteResponseImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/DeleteResponseImpl.java
index 78d9c65..983a7b5 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/DeleteResponseImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/DeleteResponseImpl.java
@@ -64,6 +64,6 @@
         sb.append( "    Delete Response\n" );
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ExtendedRequestImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ExtendedRequestImpl.java
index 8059ad2..8d2d12f 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ExtendedRequestImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ExtendedRequestImpl.java
@@ -283,6 +283,6 @@
         // The controls
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ExtendedResponseImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ExtendedResponseImpl.java
index 49c5332..7972fc5 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ExtendedResponseImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ExtendedResponseImpl.java
@@ -265,6 +265,6 @@
 
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/IntermediateResponseImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/IntermediateResponseImpl.java
index 00c781a..94aad33 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/IntermediateResponseImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/IntermediateResponseImpl.java
@@ -214,6 +214,6 @@
 
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyDnRequestImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyDnRequestImpl.java
index 2eaf131..8ea4e71 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyDnRequestImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyDnRequestImpl.java
@@ -352,6 +352,6 @@
         // The controls
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyDnResponseImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyDnResponseImpl.java
index 4477001..3951d53 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyDnResponseImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyDnResponseImpl.java
@@ -63,6 +63,6 @@
         sb.append( "    Modify Dn Response\n" );
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyRequestImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyRequestImpl.java
index b2a26fe..c46143d 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyRequestImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyRequestImpl.java
@@ -438,6 +438,6 @@
         // The controls
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyResponseImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyResponseImpl.java
index 02daeef..2df2241 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyResponseImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/ModifyResponseImpl.java
@@ -62,6 +62,6 @@
         sb.append( "    Modify Response\n" );
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchRequestImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchRequestImpl.java
index 3d0e807..c659bf8 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchRequestImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchRequestImpl.java
@@ -21,7 +21,10 @@
 
 
 import java.text.ParseException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 import org.apache.directory.shared.ldap.model.exception.LdapException;
 import org.apache.directory.shared.ldap.model.exception.LdapProtocolErrorException;
@@ -604,6 +607,6 @@
         // The controls
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
\ No newline at end of file
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultDoneImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultDoneImpl.java
index aa8d805..4057bd6 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultDoneImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultDoneImpl.java
@@ -105,6 +105,6 @@
         sb.append( "    Search Result Done\n" );
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultEntryImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultEntryImpl.java
index c88ecbb..33efefa 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultEntryImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultEntryImpl.java
@@ -185,7 +185,6 @@
             }
         }
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
-
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultReferenceImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultReferenceImpl.java
index 5bb29eb..8189a64 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultReferenceImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/SearchResultReferenceImpl.java
@@ -168,8 +168,6 @@
             }
         }
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
-
-
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/UnbindRequestImpl.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/UnbindRequestImpl.java
index 559f1c5..acfa78f 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/UnbindRequestImpl.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/UnbindRequestImpl.java
@@ -70,6 +70,6 @@
         // The controls
         sb.append( super.toString() );
 
-        return sb.toString();
+        return super.toString( sb.toString() );
     }
 }
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/AddNoDResponse.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/AddNoDResponse.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/AddNoDResponse.java
rename to ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/AddNoDResponse.java
index dcbfffb..57a9d26 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/AddNoDResponse.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/AddNoDResponse.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.extras.extended;
+package org.apache.directory.shared.ldap.model.message.extended;
 
 
 import org.apache.directory.shared.i18n.I18n;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/BindNoDResponse.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/BindNoDResponse.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/BindNoDResponse.java
rename to ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/BindNoDResponse.java
index 85b5896..b058698 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/BindNoDResponse.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/BindNoDResponse.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.extras.extended;
+package org.apache.directory.shared.ldap.model.message.extended;
 
 
 import org.apache.directory.shared.i18n.I18n;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CompareNoDResponse.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/CompareNoDResponse.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CompareNoDResponse.java
rename to ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/CompareNoDResponse.java
index 3dd88ec..ebe42b4 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/CompareNoDResponse.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/CompareNoDResponse.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.extras.extended;
+package org.apache.directory.shared.ldap.model.message.extended;
 
 
 import org.apache.directory.shared.i18n.I18n;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/DeleteNoDResponse.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/DeleteNoDResponse.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/DeleteNoDResponse.java
rename to ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/DeleteNoDResponse.java
index b7413ad..ee949c6 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/DeleteNoDResponse.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/DeleteNoDResponse.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.extras.extended;
+package org.apache.directory.shared.ldap.model.message.extended;
 
 
 import org.apache.directory.shared.i18n.I18n;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ExtendedNoDResponse.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/ExtendedNoDResponse.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ExtendedNoDResponse.java
rename to ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/ExtendedNoDResponse.java
index c0fa058..4c694eb 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ExtendedNoDResponse.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/ExtendedNoDResponse.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.extras.extended;
+package org.apache.directory.shared.ldap.model.message.extended;
 
 
 import org.apache.directory.shared.i18n.I18n;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ModifyDnNoDResponse.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/ModifyDnNoDResponse.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ModifyDnNoDResponse.java
rename to ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/ModifyDnNoDResponse.java
index 4e2034d..2250093 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ModifyDnNoDResponse.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/ModifyDnNoDResponse.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.extras.extended;
+package org.apache.directory.shared.ldap.model.message.extended;
 
 
 import org.apache.directory.shared.i18n.I18n;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ModifyNoDResponse.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/ModifyNoDResponse.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ModifyNoDResponse.java
rename to ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/ModifyNoDResponse.java
index a07f54d..5d84ec1 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/ModifyNoDResponse.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/ModifyNoDResponse.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.extras.extended;
+package org.apache.directory.shared.ldap.model.message.extended;
 
 
 import org.apache.directory.shared.i18n.I18n;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/NoticeOfDisconnect.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/NoticeOfDisconnect.java
similarity index 98%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/NoticeOfDisconnect.java
rename to ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/NoticeOfDisconnect.java
index c168931..7feee89 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/NoticeOfDisconnect.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/NoticeOfDisconnect.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.extras.extended;
+package org.apache.directory.shared.ldap.model.message.extended;
 
 
 import org.apache.directory.shared.i18n.I18n;
diff --git a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/SearchNoDResponse.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/SearchNoDResponse.java
similarity index 97%
rename from ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/SearchNoDResponse.java
rename to ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/SearchNoDResponse.java
index 7ac77eb..f332c69 100644
--- a/ldap-codec/src/main/java/org/apache/directory/shared/ldap/extras/extended/SearchNoDResponse.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/message/extended/SearchNoDResponse.java
@@ -17,7 +17,7 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.shared.ldap.extras.extended;
+package org.apache.directory.shared.ldap.model.message.extended;
 
 
 import org.apache.directory.shared.i18n.I18n;
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/Dn.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/Dn.java
index 6f4a506..20e45c0 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/Dn.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/Dn.java
@@ -21,7 +21,6 @@
 package org.apache.directory.shared.ldap.model.name;
 
 
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -60,7 +59,7 @@
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class Dn implements Cloneable, Serializable, Comparable<Dn>, Iterable<Rdn>
+public final class Dn implements Iterable<Rdn>
 {
     /** The LoggerFactory used by this class */
     protected static final Logger LOG = LoggerFactory.getLogger( Dn.class );
@@ -83,8 +82,6 @@
     /** A flag used to tell if the Dn has been normalized */
     private AtomicBoolean normalized;
 
-    // ~ Static fields/initializers
-    // -----------------------------------------------------------------
     /**
      *  The RDNs that are elements of the Dn
      * NOTE THAT THESE ARE IN THE OPPOSITE ORDER FROM THAT IMPLIED BY THE JAVADOC!
@@ -109,6 +106,9 @@
     /** 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 transient SchemaManager schemaManager;
 
@@ -155,9 +155,6 @@
     }
 
 
-    // ~ Methods
-    // ------------------------------------------------------------------------------------
-
     /**
      * Construct an empty Dn object
      */
@@ -168,11 +165,13 @@
 
 
     /**
-     * Construct an empty Dn object
+     * Construct an empty Schema aware Dn object
+     * 
+     *  @param schemaManager The SchemaManager to use
      */
-    public Dn(SchemaManager schemaManger)
+    public Dn( SchemaManager schemaManager )
     {
-        this.schemaManager = schemaManger;
+        this.schemaManager = schemaManager;
         upName = "";
         normName = "";
         normalized = new AtomicBoolean( true );
@@ -180,72 +179,13 @@
 
 
     /**
-     * @see #Dn(Dn, SchemaManager)
-     */
-    public Dn(Dn dn) throws LdapInvalidDnException
-    {
-        this( dn, null );
-    }
-
-
-    /**
-     * Copies a Dn to an Dn.
+     * Creates a new Schema aware DN from the given String
      *
-     * @param dn composed of String name components.
-     * @param schemaManager the schema manager
-     * @throws LdapInvalidDnException If the Name is invalid.
-     */
-    public Dn(Dn dn, SchemaManager schemaManager) throws LdapInvalidDnException
-    {
-        this.schemaManager = schemaManager;
-
-        if ( ( dn != null ) && ( dn.size() != 0 ) )
-        {
-            for ( Rdn rdn : dn )
-            {
-                rdns.add( 0, rdn.clone() );
-            }
-        }
-
-        toUpName();
-
-        normalized = new AtomicBoolean();
-
-        if ( schemaManager != null )
-        {
-            normalize( schemaManager.getNormalizerMapping() );
-        }
-        else
-        {
-            normalizeInternal();
-            normalized.set( false );
-        }
-    }
-
-
-    /**
-     * @see #Dn(String, SchemaManager)
-     */
-    public Dn(String upName) throws LdapInvalidDnException
-    {
-        this( upName, null );
-    }
-
-
-    /**
-     * Parse a String and checks that it is a valid Dn <br>
-     * <p>
-     * &lt;distinguishedName&gt; ::= &lt;name&gt; | e <br>
-     * &lt;name&gt; ::= &lt;name-component&gt; &lt;name-components&gt; <br>
-     * &lt;name-components&gt; ::= &lt;spaces&gt; &lt;separator&gt;
-     * &lt;spaces&gt; &lt;name-component&gt; &lt;name-components&gt; | e <br>
-     * </p>
-     *
-     * @param upName The String that contains the Dn.
      * @param schemaManager the schema manager (optional)
+     * @param upName The String that contains the Dn
      * @throws LdapInvalidNameException if the String does not contain a valid Dn.
-     */
-    public Dn(String upName, SchemaManager schemaManager) throws LdapInvalidDnException
+     *
+    public Dn( SchemaManager schemaManager, String upName ) throws LdapInvalidDnException
     {
         if ( upName != null )
         {
@@ -273,7 +213,26 @@
 
 
     /**
-     * @see #Dn(SchemaManager, String...)
+     * 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
+     * @throws LdapInvalidDnException
      */
     public Dn(String... upRdns) throws LdapInvalidDnException
     {
@@ -286,23 +245,24 @@
      * 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.
+     * 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(
+     * Dn dn = new Dn( DefaultSchemaManager.INSTANCE,
      *     "cn=Test",
      *     "ou", exampleName,
      *     baseDn);
      * </pre>
-     *
      * @param schemaManager the schema manager
      * @param upRdns
      * @throws LdapInvalidDnException
      */
-    public Dn(SchemaManager schemaManager, String... upRdns) throws LdapInvalidDnException
+    public Dn( SchemaManager schemaManager, String... upRdns ) throws LdapInvalidDnException
     {
         StringBuilder sb = new StringBuilder();
         boolean valueExpected = false;
@@ -310,6 +270,11 @@
 
         for ( String upRdn : upRdns )
         {
+            if ( Strings.isEmpty( upRdn ) )
+            {
+                continue;
+            }
+            
             if ( isFirst )
             {
                 isFirst = false;
@@ -335,8 +300,8 @@
                 valueExpected = false;
             }
         }
-
-        if ( valueExpected )
+        
+        if ( !isFirst && valueExpected )
         {
             throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, I18n.err( I18n.ERR_04202 ) );
         }
@@ -379,44 +344,137 @@
 
 
     /**
-     * Creates a Dn.
+     * Creates a Dn from a list of Rdns.
      *
-     * Note: This is mostly used internally in the server
-     *
-     * @param upName The user provided name
-     * @param normName the normalized name
-     * @param bytes the name as a byte[]
-     * @param rdnList the list of RDNs present in the Dn
+     * @param rdns the list of Rdns to be used for the Dn
      */
-    public Dn(String upName, String normName, byte[] bytes, List<Rdn> rdnList)
+    public Dn( Rdn... rdns )
     {
-        this( upName, normName, bytes );
-        rdns.addAll( rdnList );
+        if ( rdns == null )
+        {
+            return;
+        }
+        
+        for ( Rdn rdn : rdns)
+        {
+            this.rdns.add( rdn.clone() );
+        }
+
+        normalizeInternal();
+        toUpName();
+        normalized = new AtomicBoolean( false );
     }
 
 
     /**
+     * Creates a Dn concatenating a Rdn and a Dn.
      *
-     * Creates a Dn by based on the given Rdn.
-     *
-     * @param rdn the Rdn to be used in the Dn
+     * @param rdns the list of Rdns to be used for the Dn
      */
-    public Dn(Rdn rdn)
+    public Dn( Rdn rdn, Dn dn ) throws LdapInvalidDnException
     {
-        rdns.add( rdn.clone() );
-
-        if ( rdn.isNormalized() )
+        if ( ( dn == null ) || ( rdn == null ) )
         {
-            this.normName = rdn.getNormName();
-            this.upName = rdn.getName();
-            this.bytes = Strings.getBytesUtf8(normName);
-            normalized = new AtomicBoolean( true );
+            throw new IllegalArgumentException( "Either the dn or the rdn is null" );
+        }
+        
+        for ( Rdn rdnParent : dn )
+        {
+            rdns.add( rdnParent );
+        }
+        
+        rdns.add( rdn );
+        
+        normalized = new AtomicBoolean();
+        schemaManager = dn.schemaManager;
+
+        if ( schemaManager != null )
+        {
+            normalize( schemaManager.getNormalizerMapping() );
         }
         else
         {
+            normalized.set( false );
+
+            // Stores the representations of a Dn : internal (as a string and as a
+            // byte[]) and external.
+            normalizeInternal();
+        }
+
+        toUpName();
+    }
+
+
+    /**
+     * Creates a Dn concatenating a Rdn and a Dn.
+     *
+     * @param rdns the list of Rdns to be used for the Dn
+     */
+    public Dn( SchemaManager schemaManager, Dn dn ) throws LdapInvalidDnException
+    {
+        if ( dn == null )
+        {
+            throw new IllegalArgumentException( "The dn is null" );
+        }
+        
+        for ( Rdn rdnParent : dn )
+        {
+            rdns.add( rdnParent );
+        }
+        
+        normalized = new AtomicBoolean();
+        this.schemaManager = schemaManager;
+
+        if ( schemaManager != null )
+        {
+            normalize( schemaManager.getNormalizerMapping() );
+        }
+        else
+        {
+            normalized.set( false );
+
+            // Stores the representations of a Dn : internal (as a string and as a
+            // byte[]) and external.
+            normalizeInternal();
+        }
+
+        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
+     */
+    public Dn( SchemaManager schemaManager, Rdn... rdns )
+    {
+        if ( rdns == null )
+        {
+            return;
+        }
+        
+        for ( Rdn rdn : rdns)
+        {
+            this.rdns.add( rdn.clone() );
+        }
+
+        try
+        {
+            normalized = new AtomicBoolean( false );
+            
+            if ( this.schemaManager != null )
+            {
+                normalize( schemaManager.getNormalizerMapping() );
+            }
+
             normalizeInternal();
             toUpName();
-            normalized = new AtomicBoolean( false );
+        }
+        catch( LdapInvalidDnException lide )
+        {
+            throw new IllegalArgumentException( lide.getMessage() );
         }
     }
 
@@ -433,10 +491,10 @@
      * @throws LdapInvalidNameException If the Dn is invalid.
      * @throws LdapInvalidDnException If something went wrong.
      */
-    /* No qualifier */static Dn normalize( String name, Map<String, OidNormalizer> oidsMap )
+    public static Dn normalize( SchemaManager schemaManager, String name )
         throws LdapInvalidDnException
     {
-        if ( ( name == null ) || ( name.length() == 0 ) || ( oidsMap == null ) || ( oidsMap.isEmpty() ) )
+        if ( ( name == null ) || ( name.length() == 0 ) || ( schemaManager == null ) )
         {
             return Dn.EMPTY_DN;
         }
@@ -446,7 +504,7 @@
         for ( Rdn rdn : newDn.rdns )
         {
             String upName = rdn.getName();
-            rdnOidToName( rdn, oidsMap );
+            rdnOidToName( rdn, schemaManager.getNormalizerMapping() );
             rdn.normalize();
             rdn.setUpName( upName );
         }
@@ -509,14 +567,37 @@
             return normName;
         }
     }
+    
+    
+    /**
+     * Get the associated SchemaManager if any.
+     * 
+     * @return The SchemaManager
+     */
+    public SchemaManager getSchemaManager()
+    {
+        return schemaManager;
+    }
+    
+    
+    /**
+     * Tells if the Dn is schema aware.
+     * 
+     * @return <code>true</code> If the Dn has a schemaManager
+     */
+    public boolean hasSchemaManager()
+    {
+        return schemaManager != null;
+    }
 
 
     /**
-     * Return the normalized Dn as a String. It returns the same value as the
-     * getNormName method
+     * Return the user provided Dn as a String. It returns the same value as the
+     * getName method
      *
-     * @return A String representing the normalized Dn
+     * @return A String representing the user provided Dn
      */
+    @Override
     public String toString()
     {
         return getName();
@@ -667,6 +748,7 @@
      * @see java.lang.Object#hashCode()
      * @return the instance hash code
      */
+    @Override
     public int hashCode()
     {
         int result = 37;
@@ -681,9 +763,9 @@
 
 
     /**
-     * Get the initial Dn
+     * Get the user provided Dn
      *
-     * @return The Dn as a String
+     * @return The user provided Dn as a String
      */
     public String getName()
     {
@@ -698,14 +780,19 @@
      *
      * @param upName the new up name
      */
-    void setUpName( String upName )
+    /* No qualifier */ void setUpName( String upName )
     {
         this.upName = upName;
     }
 
 
     /**
-     * Get the normalized Dn
+     * 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>
      *
      * @return The Dn as a String
      */
@@ -721,7 +808,8 @@
 
 
     /**
-     * {@inheritDoc}
+     * Get the number of RDNs present in the DN
+     * @return The umber of RDNs in the DN
      */
     public int size()
     {
@@ -755,17 +843,17 @@
 
     /**
      * Tells if the current Dn is a parent of another Dn.<br>
-     * For instance, <b>dc=com</b> is a parent
+     * 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 isParentOf( String dn )
+    public boolean isAncestorOf( String dn )
     {
         try
         {
-            return isParentOf( new Dn( dn ) );
+            return isAncestorOf( new Dn( dn ) );
         }
         catch ( LdapInvalidDnException lide )
         {
@@ -776,36 +864,36 @@
 
     /**
      * Tells if the current Dn is a parent of another Dn.<br>
-     * For instance, <b>dc=com</b> is a parent
+     * 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 isParentOf( Dn dn )
+    public boolean isAncestorOf( Dn dn )
     {
         if ( dn == null )
         {
             return false;
         }
 
-        return dn.isChildOf( this );
+        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 child
+     * 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 isChildOf( String dn )
+    public boolean isDescendantOf( String dn )
     {
         try
         {
-            return isChildOf( new Dn( dn ) );
+            return isDescendantOf( new Dn( dn ) );
         }
         catch ( LdapInvalidDnException lide )
         {
@@ -816,13 +904,13 @@
 
     /**
      * Tells if a Dn is a child of another Dn.<br>
-     * For instance, <b>dc=example, dc=apache, dc=com</b> is a child
+     * 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 isChildOf( Dn dn )
+    public boolean isDescendantOf( Dn dn )
     {
         if ( ( dn == null ) || dn.isRootDSE() )
         {
@@ -854,53 +942,6 @@
 
 
     /**
-     * Determines whether this name has a specific suffix. A name
-     * <tt>name</tt> has a Dn as a suffix if its right part contains the given Dn
-     *
-     * Be aware that for a specific
-     * Dn like : <b>cn=xxx, ou=yyy</b> the hasSuffix method will return false with
-     * <b>ou=yyy</b>, and true with <b>cn=xxx</b>
-     *
-     * @param dn the name to check
-     * @return true if <tt>dn</tt> is a suffix of this name, false otherwise
-     */
-    public boolean hasSuffix( Dn dn )
-    {
-        if ( dn == null )
-        {
-            return true;
-        }
-
-        if ( dn.size() == 0 )
-        {
-            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 = 0; i < dn.size(); i++ )
-        {
-            Rdn nameRdn = dn.rdns.get( i );
-            Rdn ldapRdn = rdns.get( i );
-
-            if ( nameRdn.compareTo( ldapRdn ) != 0 )
-            {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-
-    /**
      * Tells if the Dn contains no Rdn
      *
      * @return <code>true</code> if the Dn is empty
@@ -923,32 +964,6 @@
 
 
     /**
-     * Get the given Rdn as a String. The position is used in the
-     * reverse order. Assuming that we have a Dn like
-     * <pre>dc=example,dc=apache,dc=org</pre>
-     * then :
-     * <li><code>get(0)</code> will return dc=org</li>
-     * <li><code>get(1)</code> will return dc=apache</li>
-     * <li><code>get(2)</code> will return dc=example</li>
-     *
-     * @param posn The position of the wanted Rdn in the Dn.
-     */
-    public String get( int posn )
-    {
-        if ( rdns.size() == 0 )
-        {
-            return "";
-        }
-        else
-        {
-            Rdn rdn = rdns.get( rdns.size() - posn - 1 );
-
-            return rdn.getNormName();
-        }
-    }
-
-
-    /**
      * Retrieves a component of this name.
      *
      * @param posn
@@ -1004,32 +1019,165 @@
 
 
     /**
-     * {@inheritDoc}
+     * 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 getPrefix( int posn )
+    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;
         }
-
-        if ( ( posn < 0 ) || ( posn > rdns.size() ) )
+        
+        int length = ancestor.size();
+        
+        if ( length > rdns.size() )
         {
-            String message = I18n.err( I18n.ERR_04206, posn, rdns.size() );
+            String message = I18n.err( I18n.ERR_04206, length, rdns.size() );
             LOG.error( message );
             throw new ArrayIndexOutOfBoundsException( message );
         }
 
-        Dn newDn = new Dn();
-
-        for ( int i = rdns.size() - posn; i < rdns.size(); i++ )
+        Dn newDn = new Dn( schemaManager );
+        List<Rdn> rdnsAncestor = ancestor.getRdns();
+        
+        for ( int i = 0; i < ancestor.size(); i++ )
         {
-            // Don't forget to clone the rdns !
-            newDn.rdns.add( (Rdn) rdns.get( i ).clone() );
+            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 );
+            }
         }
 
-        newDn.normName = newDn.toNormName();
-        newDn.upName = getUpNamePrefix( posn );
+        for ( int i = 0; i < rdns.size() - length; i++ )
+        {
+            // Don't forget to clone the rdns !
+            newDn.rdns.add( rdns.get( i ).clone() );
+        }
+
+        newDn.toUpName();
+        newDn.toNormName();
+        newDn.normalized.set( normalized.get() );
+
+        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++ )
+        {
+            // Don't forget to clone the rdns !
+            newDn.rdns.add( rdns.get( i ).clone() );
+        }
+
+        newDn.toUpName();
+        newDn.toNormName();
         newDn.normalized.set( normalized.get() );
 
         return newDn;
@@ -1058,7 +1206,7 @@
         for ( int i = 0; i < size() - posn; i++ )
         {
             // Don't forget to clone the rdns !
-            newDn.rdns.add( (Rdn) rdns.get( i ).clone() );
+            newDn.rdns.add( rdns.get( i ).clone() );
         }
 
         newDn.normName = newDn.toNormName();
@@ -1091,7 +1239,7 @@
             return this;
         }
 
-        Dn clonedDn = clone();
+        Dn clonedDn = copy();
 
         // Concatenate the rdns
         clonedDn.rdns.addAll( clonedDn.size() - posn, dn.rdns );
@@ -1116,9 +1264,20 @@
     /**
      * {@inheritDoc}
      */
-    public Dn addAll( Dn suffix ) throws LdapInvalidDnException
+    public Dn addAll( Dn suffix )
     {
-        return addAll( rdns.size(), suffix );
+        Dn result = null;
+        
+        try
+        {
+            result = addAll( rdns.size(), suffix );
+        }
+        catch ( LdapInvalidDnException lie )
+        {
+            // Do nothing, 
+        }
+
+        return result;
     }
 
 
@@ -1132,7 +1291,7 @@
             return this;
         }
 
-        Dn clonedDn = clone();
+        Dn clonedDn = copy();
 
         // Concatenate the rdns
         clonedDn.rdns.addAll( clonedDn.size() - posn, dn.rdns );
@@ -1151,7 +1310,9 @@
         {
             if ( schemaManager != null )
             {
-                clonedDn.normalize( schemaManager );
+                clonedDn.normalize( schemaManager.getNormalizerMapping() );
+
+                normalizeInternal();
             }
             else
             {
@@ -1176,7 +1337,7 @@
             return this;
         }
 
-        Dn clonedDn = clone();
+        Dn clonedDn = copy();
 
         // We have to parse the nameComponent which is given as an argument
         Rdn newRdn = new Rdn( comp, schemaManager );
@@ -1185,7 +1346,7 @@
 
         if ( schemaManager != null )
         {
-            clonedDn.normalize( schemaManager );
+            clonedDn.normalize( schemaManager.getNormalizerMapping() );
         }
         else
         {
@@ -1194,6 +1355,7 @@
         }
 
         clonedDn.toUpName();
+        clonedDn.toNormName();
 
         return clonedDn;
     }
@@ -1207,7 +1369,7 @@
      */
     public Dn add( Rdn newRdn )
     {
-        Dn clonedDn = clone();
+        Dn clonedDn = copy();
 
         clonedDn.rdns.add( 0, newRdn.clone() );
         clonedDn.normalized.getAndSet( false );
@@ -1224,7 +1386,7 @@
             {
                 if ( schemaManager != null )
                 {
-                    clonedDn.normalize( schemaManager );
+                    clonedDn.normalize( schemaManager.getNormalizerMapping() );
                 }
                 else
                 {
@@ -1245,9 +1407,11 @@
 
 
     /**
+     * used only for deserialization.
+     * 
      * {@inheritDoc}
      */
-    public Dn add( int posn, String comp ) throws LdapInvalidDnException
+    /* No qualifier */ Dn addInternal( int posn, Rdn rdn )
     {
         if ( ( posn < 0 ) || ( posn > size() ) )
         {
@@ -1257,65 +1421,13 @@
         }
 
         // We have to parse the nameComponent which is given as an argument
-        Rdn newRdn = new Rdn( comp );
+        Rdn newRdn = rdn.clone();
 
-        Dn clonedDn = clone();
-
-        int realPos = clonedDn.size() - posn;
-        clonedDn.rdns.add( realPos, newRdn );
-
-        if ( schemaManager != null )
-        {
-            clonedDn.normalize( schemaManager );
-        }
-        else
-        {
-            clonedDn.normalizeInternal();
-            clonedDn.normalized.set( false );
-        }
-
-        clonedDn.toUpName();
-
-        return clonedDn;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public Dn remove( int posn ) throws LdapInvalidDnException
-    {
-        if ( rdns.size() == 0 )
-        {
-            return this;
-        }
-
-        if ( ( posn < 0 ) || ( posn >= rdns.size() ) )
-        {
-            String message = I18n.err( I18n.ERR_04206, posn, rdns.size() );
-            LOG.error( message );
-            throw new ArrayIndexOutOfBoundsException( message );
-        }
-
-        Dn clonedDn = clone();
-        clonedDn._removeChild( posn );
-
-        return clonedDn;
-    }
-
-
-    /**
-     * removes a child (Rdn) present at the given position
-     *
-     * @param posn the index of the child's position
-     */
-    private void _removeChild( int posn )
-    {
-        int realPos = size() - posn - 1;
-        rdns.remove( realPos );
-
-        normalizeInternal();
+        int realPos = size() - posn;
+        rdns.add( realPos, newRdn );
         toUpName();
+
+        return this;
     }
 
 
@@ -1332,33 +1444,45 @@
             return null;
         }
 
-        return getPrefix( size() - 1 );
+        if ( rdns.size() == 0 )
+        {
+            return EMPTY_DN;
+        }
+        
+        int posn = rdns.size() - 1;
+
+        Dn newDn = new Dn( schemaManager );
+
+        for ( int i = rdns.size() - posn; i < rdns.size(); i++ )
+        {
+            // Don't forget to clone the rdns !
+            newDn.rdns.add( rdns.get( i ).clone() );
+        }
+
+        newDn.normName = newDn.toNormName();
+        newDn.upName = getUpNamePrefix( posn );
+        newDn.normalized.set( normalized.get() );
+
+        return newDn;
     }
 
 
     /**
      * {@inheritDoc}
      */
-    protected Dn clone()
+    //@Override
+    private Dn copy()
     {
-        try
-        {
-            Dn dn = (Dn) super.clone();
-            dn.normalized = new AtomicBoolean( normalized.get() );
-            dn.rdns = new ArrayList<Rdn>();
+        Dn dn = new Dn( schemaManager );
+        dn.normalized = new AtomicBoolean( normalized.get() );
+        dn.rdns = new ArrayList<Rdn>();
 
-            for ( Rdn rdn : rdns )
-            {
-                dn.rdns.add( (Rdn) rdn.clone() );
-            }
-
-            return dn;
-        }
-        catch ( CloneNotSupportedException cnse )
+        for ( Rdn rdn : rdns )
         {
-            LOG.error( I18n.err( I18n.ERR_04207 ) );
-            throw new Error( I18n.err( I18n.ERR_04208 ) );
+            dn.rdns.add( rdn.clone() );
         }
+
+        return dn;
     }
 
 
@@ -1366,11 +1490,12 @@
      * @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( ( String ) obj );
+            return normName.equals( obj );
         }
         else if ( obj instanceof Dn)
         {
@@ -1399,32 +1524,6 @@
     }
 
 
-    /**
-     * {@inheritDoc}
-     */
-    public int compareTo( Dn dn )
-    {
-        if ( dn.size() != size() )
-        {
-            return size() - dn.size();
-        }
-
-        for ( int i = rdns.size(); i > 0; i-- )
-        {
-            Rdn rdn1 = rdns.get( i - 1 );
-            Rdn rdn2 = dn.rdns.get( i - 1 );
-            int res = rdn1.compareTo( rdn2 );
-
-            if ( res != 0 )
-            {
-                return res;
-            }
-        }
-
-        return EQUAL;
-    }
-
-
     private static Ava atavOidToName( Ava atav, Map<String, OidNormalizer> oidsMap )
         throws LdapInvalidDnException
     {
@@ -1493,7 +1592,7 @@
         {
             // We have more than one ATAV for this Rdn. We will loop on all
             // ATAVs
-            Rdn rdnCopy = (Rdn) rdn.clone();
+            Rdn rdnCopy = rdn.clone();
             rdn.clear();
 
             for ( Ava val : rdnCopy )
@@ -1567,7 +1666,7 @@
      * @throws LdapInvalidDnException If something went wrong.
      * @return The normalized Dn
      */
-    public Dn normalize( Map<String, OidNormalizer> oidsMap ) throws LdapInvalidDnException
+    private Dn normalize( Map<String, OidNormalizer> oidsMap ) throws LdapInvalidDnException
     {
         if ( ( oidsMap == null ) || ( oidsMap.isEmpty() ) )
         {
@@ -1653,7 +1752,24 @@
 
 
     /**
-     * {@inheritDoc}
+     * 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>
+     * <br/>
+     * will produce this output : <br/>
+     * <pre>
+     * dc=org
+     * dc=apache
+     * sn=test
+     * </pre>
+     * 
      */
     public Iterator<Rdn> iterator()
     {
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/DnSerializer.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/DnSerializer.java
index 61ec2da..d43bc3b 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/DnSerializer.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/DnSerializer.java
@@ -6,24 +6,26 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.ldap.model.name;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectInput;
+import java.io.ObjectInputStream;
 import java.io.ObjectOutput;
-import java.util.ArrayList;
-import java.util.List;
+import java.io.ObjectOutputStream;
 
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.util.Strings;
@@ -52,17 +54,47 @@
 
     /**
      * Serialize a Dn
-     * 
+     *
      * We have to store a Dn data efficiently. Here is the structure :
-     * 
+     *
      * <li>upName</li> The User provided Dn<p>
-     * <li>normName</li> May be null if the normName is equivalent to 
+     * <li>normName</li> May be null if the normName is equivalent to
      * the upName<p>
      * <li>rdns</li> The rdn's List.<p>
-     * 
+     *
      * for each rdn :
      * <li>call the Rdn write method</li>
-     * 
+     *
+     * @param dn The Dn to serialize
+     * @return a byte[] containing the serialized DN
+     * @throws IOException If we can't write in this stream
+     */
+    public static byte[] serialize( Dn dn ) throws IOException
+    {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream( baos );
+        
+        serialize( dn, out );
+        
+        out.flush();
+        
+        return baos.toByteArray();
+    }
+
+
+    /**
+     * Serialize a Dn
+     *
+     * We have to store a Dn data efficiently. Here is the structure :
+     *
+     * <li>upName</li> The User provided Dn<p>
+     * <li>normName</li> May be null if the normName is equivalent to
+     * the upName<p>
+     * <li>rdns</li> The rdn's List.<p>
+     *
+     * for each rdn :
+     * <li>call the Rdn write method</li>
+     *
      * @param dn The Dn to serialize
      * @param out the stream in which the Dn will be serialized
      * @throws IOException If we can't write in this stream
@@ -75,10 +107,10 @@
             LOG.error( message );
             throw new IOException( message );
         }
-        
+
         // Write the UPName
         Unicode.writeUTF(out, dn.getName());
-        
+
         // Write the NormName if different
         if ( dn.isNormalized() )
         {
@@ -97,13 +129,13 @@
             LOG.error( message );
             throw new IOException( message );
         }
-        
+
         // Should we store the byte[] ???
-        
+
         // Write the RDNs.
         // First the number of RDNs
         out.writeInt( dn.size() );
-        
+
         // Loop on the RDNs
         for ( Rdn rdn:dn.getRdns() )
         {
@@ -114,11 +146,31 @@
 
     /**
      * Deserialize a Dn
-     * 
+     *
      * We read back the data to create a new Dn. The structure
      * read is exposed in the {@link DnSerializer#serialize(Dn, ObjectOutput)}
      * method<p>
-     * 
+     *
+     * @param in The input bytes from which the Dn is read
+     * @return a deserialized Dn
+     * @throws IOException If the stream can't be read
+     */
+    public static Dn deserialize( byte[] bytes ) throws IOException
+    {
+        ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
+        ObjectInputStream in = new ObjectInputStream( bais );
+    
+        return deserialize( in );
+    }
+    
+
+    /**
+     * Deserialize a Dn
+     *
+     * We read back the data to create a new Dn. The structure
+     * read is exposed in the {@link DnSerializer#serialize(Dn, ObjectOutput)}
+     * method<p>
+     *
      * @param in The input stream from which the Dn is read
      * @return a deserialized Dn
      * @throws IOException If the stream can't be read
@@ -127,10 +179,10 @@
     {
         // Read the UPName
         String upName = Unicode.readUTF(in);
-        
+
         // Read the NormName
         String normName = Unicode.readUTF(in);
-        
+
         if ( normName.length() == 0 )
         {
             // As the normName is equal to the upName,
@@ -138,20 +190,20 @@
             // restore it by copying the upName.
             normName = upName;
         }
-        
+
         // Should we read the byte[] ???
         byte[] bytes = Strings.getBytesUtf8(upName);
-        
+
         // Read the RDNs. Is it's null, the number will be -1.
         int nbRdns = in.readInt();
-        
-        List<Rdn> rdnList = new ArrayList<Rdn>();
+        Dn dn = new Dn( upName, normName, bytes );
+
         for ( int i = 0; i < nbRdns; i++ )
         {
             Rdn rdn = RdnSerializer.deserialize( in );
-            rdnList.add( rdn );
+            dn = dn.addInternal( 0, rdn );
         }
-    
-        return new Dn( upName, normName, bytes, rdnList );
+
+        return dn;
     }
 }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/DnUtils.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/DnUtils.java
index 39234fa..87dd16a 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/DnUtils.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/name/DnUtils.java
@@ -20,6 +20,9 @@
 package org.apache.directory.shared.ldap.model.name;
 
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
 import org.apache.directory.shared.util.Chars;
@@ -27,9 +30,6 @@
 import org.apache.directory.shared.util.Position;
 import org.apache.directory.shared.util.Unicode;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Utility class used by the Dn Parser.
  * 
@@ -37,8 +37,6 @@
  */
 public final class DnUtils
 {
-    // ~ Static fields/initializers
-    // -----------------------------------------------------------------
     /** A value if we got an error while parsing */
     public static final int PARSING_ERROR = -1;
 
@@ -765,37 +763,6 @@
         return rdn.substring( index + 1, rdn.length() );
     }
 
-    /**
-     * Gets the relative name between an ancestor and a potential descendant.
-     * Both name arguments must be normalized. The returned name is also
-     * normalized.
-     *
-     * @param ancestor the normalized distinguished name of the ancestor context
-     * @param descendant the normalized distinguished name of the descendant context
-     * @return the relative normalized name between the ancestor and the
-     *         descendant contexts
-     * @throws org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException if the contexts are not related in the ancestual sense
-     */
-    public static Dn getRelativeName( Dn ancestor, Dn descendant ) throws LdapInvalidDnException
-    {
-        Dn rdn = descendant;
-
-        if ( rdn.isChildOf( ancestor ) )
-        {
-            for ( int ii = 0; ii < ancestor.size(); ii++ )
-            {
-                rdn = rdn.remove( 0 );
-            }
-        }
-        else
-        {
-            LdapInvalidDnException e = new LdapInvalidDnException( I18n.err(I18n.ERR_04417, descendant, ancestor) );
-
-            throw e;
-        }
-
-        return rdn;
-    }
 
     /**
      * Gets the '+' appended components of a composite name component.
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/comparators/DnComparator.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/comparators/DnComparator.java
index 43b5c8a..3a153f6 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/comparators/DnComparator.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/comparators/DnComparator.java
@@ -20,10 +20,9 @@
 package org.apache.directory.shared.ldap.model.schema.comparators;
 
 
+import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.model.exception.LdapException;
 import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
-
-import org.apache.directory.shared.i18n.I18n;
 import org.apache.directory.shared.ldap.model.name.Dn;
 import org.apache.directory.shared.ldap.model.schema.LdapComparator;
 import org.apache.directory.shared.ldap.model.schema.SchemaManager;
@@ -65,7 +64,14 @@
             return -1;
         }
         
-        return dn0.compareTo( dn1 );
+        if ( dn0.equals( dn1 ) )
+        {
+            return 0;
+        }
+        else
+        {
+            return -1;
+        }
     }
 
 
@@ -81,7 +87,7 @@
         }
         else if ( obj instanceof String )
         {
-            dn = new Dn( ( String ) obj, schemaManager );
+            dn = new Dn( schemaManager, ( String ) obj );
         }
         else
         {
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/comparators/UniqueMemberComparator.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/comparators/UniqueMemberComparator.java
index b4425b6..0dcc6cd 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/comparators/UniqueMemberComparator.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/comparators/UniqueMemberComparator.java
@@ -57,17 +57,27 @@
     /**
      * Implementation of the Compare method
      */
-    public int compare( String dnstr0, String dnstr1 )
+    public int compare( String dnstr1, String dnstr2 )
     {
-        int dash0 = dnstr0.lastIndexOf( '#' );
         int dash1 = dnstr1.lastIndexOf( '#' );
+        int dash2 = dnstr2.lastIndexOf( '#' );
 
-        if ( ( dash0 == -1 ) && ( dash1 == -1 ) )
+        if ( ( dash1 == -1 ) && ( dash2 == -1 ) )
         {
             // no UID part
             try
             {
-                return getDn( dnstr0 ).compareTo( getDn( dnstr1 ) );
+                Dn dn1 = getDn( dnstr1 );
+                Dn dn2 = getDn( dnstr2 );
+                
+                if ( dn1.equals( dn2 ) )
+                {
+                    return 0;
+                }
+                else
+                {
+                    return -1;
+                }
             }
             catch ( LdapInvalidDnException ne )
             {
@@ -77,33 +87,33 @@
         else
         {
             // Now, check that we don't have another '#'
-            if ( dnstr0.indexOf( '#' ) != dash0 )
+            if ( dnstr1.indexOf( '#' ) != dash1 )
             {
                 // Yes, we have one : this is not allowed, it should have been
                 // escaped.
                 return -1;
             }
 
-            if ( dnstr1.indexOf( '#' ) != dash0 )
+            if ( dnstr2.indexOf( '#' ) != dash1 )
             {
                 // Yes, we have one : this is not allowed, it should have been
                 // escaped.
                 return 1;
             }
 
-            Dn dn0 = null;
             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 uid0 = dnstr0.substring( dash0 + 1 );
+            String uid1 = dnstr1.substring( dash1 + 1 );
 
-            if ( dash0 > 0 )
+            if ( dash1 > 0 )
             {
                 try
                 {
-                    dn0 = new Dn( dnstr0.substring( 0, dash0 ) );
+                    dn1 = new Dn( dnstr1.substring( 0, dash1 ) );
                 }
                 catch ( LdapException ne )
                 {
@@ -118,13 +128,13 @@
             // 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 );
+            String uid2 = dnstr2.substring( dash2 + 1 );
 
-            if ( dash1 > 0 )
+            if ( dash2 > 0 )
             {
                 try
                 {
-                    dn1 = new Dn( dnstr0.substring( 0, dash1 ) );
+                    dn2 = new Dn( dnstr1.substring( 0, dash2 ) );
                 }
                 catch ( LdapException ne )
                 {
@@ -136,14 +146,12 @@
                 return 1;
             }
 
-            int dnComp = dn0.compareTo( dn1 );
-
-            if ( dnComp != 0 )
+            if ( dn1.equals( dn2 ) )
             {
-                return dnComp;
+                return uid1.compareTo( uid2 );
             }
 
-            return uid0.compareTo( uid1 );
+            return -1;
         }
     }
 
@@ -169,7 +177,7 @@
         }
         else if ( obj instanceof String )
         {
-            dn = new Dn( ( String ) obj, schemaManager );
+            dn = new Dn( schemaManager, ( String ) obj );
         }
         else
         {
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/normalizers/DnNormalizer.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/normalizers/DnNormalizer.java
index 28d9468..342cb7e 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/normalizers/DnNormalizer.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/normalizers/DnNormalizer.java
@@ -60,7 +60,7 @@
         
         String dnStr = value.getString();
         
-        dn = new Dn( dnStr, schemaManager );
+        dn = new Dn( schemaManager, dnStr );
         
         return new StringValue( dn.getNormName() );
     }
@@ -73,7 +73,7 @@
     {
         Dn dn = null;
         
-        dn = new Dn( value, schemaManager );
+        dn = new Dn( schemaManager, value );
         
         return dn.getNormName();
     }
@@ -89,7 +89,7 @@
     {
         Dn dn = null;
         
-        dn = new Dn( value, schemaManager );
+        dn = value.normalize( schemaManager );
         
         return dn.getNormName();
     }
diff --git a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/normalizers/UniqueMemberNormalizer.java b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/normalizers/UniqueMemberNormalizer.java
index dc1b1aa..0d7f6ff 100644
--- a/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/normalizers/UniqueMemberNormalizer.java
+++ b/ldap-model/src/main/java/org/apache/directory/shared/ldap/model/schema/normalizers/UniqueMemberNormalizer.java
@@ -80,7 +80,7 @@
             
             if ( sharpPos > 0 )
             {
-                Dn dn = new Dn( nameAndUid.substring( 0, sharpPos ), schemaManager );
+                Dn dn = new Dn( schemaManager, nameAndUid.substring( 0, sharpPos ) );
                 
                 return new StringValue( dn.getNormName() + '#' + uid );
             }
@@ -125,7 +125,7 @@
             
             if ( sharpPos > 0 )
             {
-                Dn dn = new Dn( value.substring( 0, sharpPos ), schemaManager );
+                Dn dn = new Dn( schemaManager, value.substring( 0, sharpPos ) );
                 
                 return dn.getNormName() + '#' + uid;
             }
@@ -138,7 +138,7 @@
         {
             // No UID, the strValue is a Dn
             // Return the normalized Dn
-            return new Dn( value, schemaManager ).getNormName();
+            return new Dn( schemaManager, value ).getNormName();
         }
     }
 
diff --git a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/filter/LdapUrlTest.java b/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/filter/LdapUrlTest.java
index 8f61d7c..414adb8 100644
--- a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/filter/LdapUrlTest.java
+++ b/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/filter/LdapUrlTest.java
@@ -6,16 +6,16 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.ldap.model.filter;
 
@@ -30,8 +30,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
 import org.apache.directory.shared.ldap.model.exception.LdapURLEncodingException;
 import org.apache.directory.shared.ldap.model.filter.LdapURL.Extension;
@@ -39,10 +37,13 @@
 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)
@@ -611,7 +612,7 @@
     @Test
     public void testLdapRFC2255_6() throws LdapURLEncodingException
     {
-        assertEquals( "ldap://ldap.question.com/o=Question%3f,c=US?mail", new LdapURL(
+        assertEquals( "ldap://ldap.question.com/o=Question%3F,c=US?mail", new LdapURL(
             "ldap://ldap.question.com/o=Question%3f,c=US?mail" ).toString() );
     }
 
@@ -622,7 +623,7 @@
     @Test
     public void testLdapRFC2255_7() throws LdapURLEncodingException
     {
-        assertEquals( "ldap://ldap.netscape.com/o=Babsco,c=US???(int=%5c00%5c00%5c00%5c04)", new LdapURL(
+        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() );
     }
 
@@ -2057,7 +2058,7 @@
 
 
     /**
-     * Test the extension order of an LdapURL. 
+     * Test the extension order of an LdapURL.
      */
     @Test
     public void testLdapURLExtensionOrder()
@@ -2118,13 +2119,13 @@
         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
+        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
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=%C3%84%C3%96%C3%9C%C3%9F%C3%A4%C3%B6%C3%BC", url2
             .toString() );
     }
 
@@ -2150,14 +2151,14 @@
 
     /**
      * 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
@@ -2167,17 +2168,17 @@
         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() );
+        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() );
+        assertEquals( "ldap://localhost:123/????X-CONNECTION-NAME=:/%3F#[]@!$&'()*+%2c;=", url2.toString() );
     }
 
 
     /**
      * Test with RFC 3986 unreserved characters in extension value.
-     * 
+     *
      *   unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
      */
     @Test
diff --git a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/message/controls/OpaqueControlTest.java b/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/message/controls/OpaqueControlTest.java
new file mode 100644
index 0000000..3e70f75
--- /dev/null
+++ b/ldap-model/src/test/java/org/apache/directory/shared/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.shared.ldap.model.message.controls;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.directory.shared.ldap.model.message.controls.OpaqueControl;
+import org.apache.directory.shared.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/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnParserTest.java b/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnParserTest.java
index 6a86eba..79649d7 100644
--- a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnParserTest.java
+++ b/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnParserTest.java
@@ -20,20 +20,19 @@
 package org.apache.directory.shared.ldap.model.name;
 
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+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.shared.ldap.model.exception.LdapException;
 import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
-import org.apache.directory.shared.ldap.model.name.Dn;
-import org.apache.directory.shared.ldap.model.name.DnParser;
 import org.apache.directory.shared.util.Strings;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import static org.junit.Assert.fail;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertNotNull;
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 
 
 /**
@@ -45,11 +44,7 @@
 @Concurrency()
 public class DnParserTest
 {
-    // ~ Methods
-    // ------------------------------------------------------------------------------------
-
     // CONSTRUCTOR functions --------------------------------------------------
-
     /**
      * test an empty Dn
      */
diff --git a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnUtilsTest.java b/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnUtilsTest.java
index 0063794..ebced6e 100644
--- a/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnUtilsTest.java
+++ b/ldap-model/src/test/java/org/apache/directory/shared/ldap/model/name/DnUtilsTest.java
@@ -22,16 +22,14 @@
 
 import static org.junit.Assert.assertEquals;
 
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
 import org.apache.directory.shared.ldap.model.exception.LdapException;
-import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException;
-import org.apache.directory.shared.ldap.model.name.Dn;
-import org.apache.directory.shared.ldap.model.name.DnUtils;
 import org.apache.directory.shared.util.Strings;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
 
 
 /**
@@ -194,20 +192,4 @@
         assertEquals( "expecting one part : ", 1, args.length );
         assertEquals( "cn=Alex", args[0] );
     }
-
-
-    @Test
-    public void testGetRelativeName() throws LdapInvalidDnException
-    {
-        // test the basis case first with the root
-        Dn ancestor = new Dn( "" );
-        Dn descendant = new Dn( "ou=system" );
-        Dn relativeName = DnUtils.getRelativeName(ancestor, descendant);
-        assertEquals( relativeName.toString(), "ou=system" );
-
-        ancestor = new Dn( "ou=system" );
-        descendant = new Dn( "ou=users,ou=system" );
-        relativeName = DnUtils.getRelativeName(ancestor, descendant);
-        assertEquals( relativeName.toString(), "ou=users" );
-    }
 }
diff --git a/ldap-schema-converter/pom.xml b/ldap-schema-converter/pom.xml
index b522c11..76e1715 100644
--- a/ldap-schema-converter/pom.xml
+++ b/ldap-schema-converter/pom.xml
@@ -56,6 +56,11 @@
       <groupId>${project.groupId}</groupId>
       <artifactId>shared-util</artifactId>
     </dependency>
+    
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
diff --git a/ldap-schema/pom.xml b/ldap-schema/pom.xml
index fd398cb..17f0c76 100644
--- a/ldap-schema/pom.xml
+++ b/ldap-schema/pom.xml
@@ -48,7 +48,7 @@
 
     <dependency>
       <groupId>${project.groupId}</groupId>
-      <artifactId>shared-ldap</artifactId>
+      <artifactId>shared-ldap-extras-aci</artifactId>
     </dependency>
 
     <dependency>
diff --git a/ldap-schema/src/main/java/org/apache/directory/shared/ldap/schemaloader/JarLdifSchemaLoader.java b/ldap-schema/src/main/java/org/apache/directory/shared/ldap/schemaloader/JarLdifSchemaLoader.java
index 394c6db..fe0e940 100644
--- a/ldap-schema/src/main/java/org/apache/directory/shared/ldap/schemaloader/JarLdifSchemaLoader.java
+++ b/ldap-schema/src/main/java/org/apache/directory/shared/ldap/schemaloader/JarLdifSchemaLoader.java
@@ -71,7 +71,7 @@
 
     /** 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.*" ) );
+        .compile( "schema" + SEPARATOR_PATTERN + "ou=schema.*" ) );
 
 
     /**
@@ -114,7 +114,7 @@
             LOG.debug( "Initializing schema" );
         }
 
-        Pattern pat = Pattern.compile( ".*schema" + SEPARATOR_PATTERN + "ou=schema"
+        Pattern pat = Pattern.compile( "schema" + SEPARATOR_PATTERN + "ou=schema"
                 + SEPARATOR_PATTERN + "cn=[a-z0-9-_]*\\." + LDIF_EXT );
 
         for ( String file : RESOURCE_MAP.keySet() )
@@ -157,10 +157,10 @@
      * @param schema the schema to get the path for
      * @return the regex.Pattern fragment for the path for the specified schema directory
      */
-    private String getSchemaDirectory( Schema schema )
+    private String getSchemaDirectoryString( Schema schema )
     {
-        return "schema" + SEPARATOR_PATTERN + "ou=schema" + SEPARATOR_PATTERN
-                        + "cn=" + Strings.lowerCase(schema.getSchemaName()) + SEPARATOR_PATTERN;
+        return "schema" + File.separator + "ou=schema" + File.separator
+                        + "cn=" + Strings.lowerCase(schema.getSchemaName()) + File.separator;
     }
 
 
@@ -178,12 +178,13 @@
 
         for ( Schema schema : schemas )
         {
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.COMPARATORS_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.COMPARATORS_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "comparator LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -213,12 +214,13 @@
 
         for ( Schema schema : schemas )
         {
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.SYNTAX_CHECKERS_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.SYNTAX_CHECKERS_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "syntaxChecker LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -248,12 +250,13 @@
 
         for ( Schema schema : schemas )
         {
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.NORMALIZERS_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.NORMALIZERS_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "normalizer LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -283,12 +286,13 @@
 
         for ( Schema schema : schemas )
         {
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.MATCHING_RULES_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.MATCHING_RULES_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "matchingRules LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -318,12 +322,13 @@
 
         for ( Schema schema : schemas )
         {
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.SYNTAXES_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.SYNTAXES_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "syntax LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -354,13 +359,14 @@
         for ( Schema schema : schemas )
         {
             // check that the attributeTypes directory exists for the schema
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.ATTRIBUTES_TYPE_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
-
+            String start = getSchemaDirectoryString( schema )
+                    + SchemaConstants.ATTRIBUTES_TYPE_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
+            
             // get list of attributeType LDIF schema files in attributeTypes
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "attributeType LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -390,12 +396,13 @@
 
         for ( Schema schema : schemas )
         {
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.MATCHING_RULE_USE_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.MATCHING_RULE_USE_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "matchingRuleUse LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -425,12 +432,13 @@
 
         for ( Schema schema : schemas )
         {
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.NAME_FORMS_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.NAME_FORMS_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "nameForm LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -460,12 +468,13 @@
 
         for ( Schema schema : schemas )
         {
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.DIT_CONTENT_RULES_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.DIT_CONTENT_RULES_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "ditContentRule LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -495,13 +504,13 @@
 
         for ( Schema schema : schemas )
         {
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.DIT_STRUCTURE_RULES_PATH
-                                                + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.DIT_STRUCTURE_RULES_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "ditStructureRule LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
@@ -532,12 +541,13 @@
         for ( Schema schema : schemas )
         {
             // get objectClasses directory, check if exists, return if not
-            Pattern regex = Pattern.compile( ".*" + getSchemaDirectory( schema )
-                    + SchemaConstants.OBJECT_CLASSES_PATH + SEPARATOR_PATTERN + "m-oid=.*\\." + LDIF_EXT );
+            String start = getSchemaDirectoryString( schema )
+                + SchemaConstants.OBJECT_CLASSES_PATH + File.separator + "m-oid=";
+            String end = "." + LDIF_EXT;
 
             for ( String resourcePath : RESOURCE_MAP.keySet() )
             {
-                if ( regex.matcher( resourcePath ).matches() )
+                if ( resourcePath.startsWith( start ) && resourcePath.endsWith( end ) )
                 {
                     URL resource = getResource( resourcePath, "objectClass LDIF file" );
                     LdifReader reader = new LdifReader( resource.openStream() );
diff --git a/ldap-schema/src/main/java/org/apache/directory/shared/ldap/schemamanager/impl/DefaultSchemaManager.java b/ldap-schema/src/main/java/org/apache/directory/shared/ldap/schemamanager/impl/DefaultSchemaManager.java
index c938cb4..4eff5ae 100644
--- a/ldap-schema/src/main/java/org/apache/directory/shared/ldap/schemamanager/impl/DefaultSchemaManager.java
+++ b/ldap-schema/src/main/java/org/apache/directory/shared/ldap/schemamanager/impl/DefaultSchemaManager.java
@@ -80,6 +80,7 @@
 import org.apache.directory.shared.ldap.model.schema.registries.Schema;
 import org.apache.directory.shared.ldap.model.schema.registries.SchemaLoader;
 import org.apache.directory.shared.ldap.model.schema.registries.SyntaxCheckerRegistry;
+import org.apache.directory.shared.ldap.schemaloader.JarLdifSchemaLoader;
 import org.apache.directory.shared.ldap.schemaloader.SchemaEntityFactory;
 import org.apache.directory.shared.util.Strings;
 import org.apache.directory.shared.util.exception.NotImplementedException;
@@ -127,6 +128,23 @@
 
     /** Two flags for RELAXED and STRICT, this is RELAXED */
     public static final boolean RELAXED = true;
+    
+    /**
+     * 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( this );
+        factory = new SchemaEntityFactory();
+        isRelaxed = STRICT;
+        loadAllEnabled();
+    }
 
 
     /**
@@ -137,7 +155,7 @@
     public DefaultSchemaManager( SchemaLoader loader )
     {
         // Default to the the root (one schemaManager for all the entries
-        namingContext = Dn.EMPTY_DN;
+        namingContext = Dn.ROOT_DSE;
         this.schemaLoader = loader;
         errors = new ArrayList<Throwable>();
         registries = new Registries( this );
@@ -1376,8 +1394,7 @@
         try
         {
             schemaModificationAttributesDn = new Dn( SchemaConstants.SCHEMA_MODIFICATIONS_DN );
-            schemaModificationAttributesDn
-                .normalize( getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
+            schemaModificationAttributesDn.normalize( new DefaultSchemaManager() );
         }
         catch ( LdapInvalidDnException e )
         {
diff --git a/ldap/pom.xml b/ldap/pom.xml
deleted file mode 100644
index 6bd6661..0000000
--- a/ldap/pom.xml
+++ /dev/null
@@ -1,163 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-  
-  http://www.apache.org/licenses/LICENSE-2.0
-  
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT 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.shared</groupId>
-    <artifactId>shared-parent</artifactId>
-    <version>1.0.0-M2-SNAPSHOT</version>
-  </parent>
-  
-  <artifactId>shared-ldap</artifactId>
-  <name>Apache Directory Shared LDAP</name>
-  <packaging>bundle</packaging>
-  <description>Common LDAP 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>shared-util</artifactId>
-    </dependency> 
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>shared-asn1-api</artifactId>
-    </dependency> 
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>shared-asn1-ber</artifactId>
-    </dependency> 
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>shared-i18n</artifactId>
-    </dependency> 
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>shared-ldap-model</artifactId>
-    </dependency> 
-
-    <dependency>
-      <groupId>${project.groupId}</groupId>
-      <artifactId>shared-ldap-codec</artifactId>
-    </dependency> 
-
-    <dependency>
-      <groupId>org.apache.mina</groupId>
-      <artifactId>mina-core</artifactId>
-    </dependency>
-    
-    <dependency>
-      <groupId>antlr</groupId>
-      <artifactId>antlr</artifactId>
-    </dependency>
-    
-    <dependency>
-      <groupId>commons-lang</groupId>
-      <artifactId>commons-lang</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>commons-collections</groupId>
-      <artifactId>commons-collections</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.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</Bundle-SymbolicName>
-            <Export-Package>
-              org.apache.directory.shared.ldap.aci*,
-              org.apache.directory.shared.ldap.message*,
-              org.apache.directory.shared.ldap.sp,
-              org.apache.directory.shared.ldap.trigger,
-              org.apache.directory.shared.ldap.util*
-            </Export-Package>
-          </instructions>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-</project>
diff --git a/ldap/xdocs/index.xml b/ldap/xdocs/index.xml
deleted file mode 100644
index 9a173a9..0000000
--- a/ldap/xdocs/index.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-<document>
-  <properties>
-    <author email="jmachols@apache.org">Jeff Machols</author>
-    <title>Apache Directory Project: LDAP Common Code</title>
-  </properties>
-  
-  <body>
-    <section name="Overview">
-      <p>LDAP Common Code</p>
-      <p> 
-      This project contains code and utilities common to the LDAP protocol.
-      </p>
-    </section>
-    <section name="LDAP Common Packages">
-      <subsection name="Filter">
-        <p>
-          The filter package will parsese and LDAP expression into 
-          a filter expression tree as defined in <a href="http://www.ietf.org/rfc/rfc2254.txt">RFC 2254</a>
-        </p>  
-      </subsection>
-        
-      <subsection name="LDIF">
-        <p>
-          The The LDAP Data Interchange Format (LDIF) parsing 
-          package Parses an LDIF into a multimap or a JNDI 
-          Attributes instance of attributeToPropertyMapping key/value pairs with
-          potential more than one attributeToPropertyMapping value per attributeToPropertyMapping.
-          This parser populates the MultiMap or Attributes 
-          instance with all attributeToPropertyMappings within the LDIF including
-          control attributeToPropertyMappings like the 'dn' and the changeType.
-        </p>
-        <p>
-          The package contain an LDIF entry class that can be used.  Along
-          with the parsing utility, the embedding application can LDIF
-          parsing and management without becomming an expert on the RFC.
-          Addition details about LDIF can be obtained from the 
-          <a href="http://www.ietf.org/rfc/rfc2849.txt">LDIF RFC</a>
-        </p>        
-      </subsection>
-      
-      <subsection name="Message">
-      	<p>
-          The LDAP Common Messaging package provides a framework for
-          all LDAP request and response messages.  Each of the reponses
-          and requests have an implementation.
-      	</p>
-      </subsection>
-      
-      <subsection name="Name">
-        <p>
-          This package provides LDAP distinguished name creation and 
-          normalization.  This provides a common method for ensuring 
-          you are creating the entry DN correctly.  Failure to properly
-          create and normalize the DN of an entry will result in unpredicatble
-          results when operations are performed on the entry.  
-        </p>
-      </subsection>
-      
-    </section>
-  </body>
-</document>
diff --git a/ldap/xdocs/navigation.xml b/ldap/xdocs/navigation.xml
deleted file mode 100644
index 1a034b2..0000000
--- a/ldap/xdocs/navigation.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT 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>
-
- <title>LDAP Shared</title>
-
- <body>
-
-    <links>
-      <item name="Directory" href="../../../index.html"/>
-      <item name="ApacheDS" href="../../apacheds/index.html"/>
-      <item name="LDAP" href="../../ldap.html"/>
-      <item name="Naming" href="../../naming/index.html"/>
-      <item name="ASN.1" href="../../asn1/index.html"/>
-      <item name="Kerberos" href="../../../subprojects/kerberos.html"/>
-      <item name="AuthX" href="../../authx/index.html"/>
-      <item name="MINA" href="../../network/index.html"/>
-      <item name="Protocols" href="../../providers.html"/>
-    </links>
-
-    <menu name="LDAP">
-      <item name="Overview" href="/index.html"/>
-    </menu>
-    
-    <menu name="Project Information">
-      <item name="Wiki" href="http://wiki.apache.org/directory"/>
-      <item name="Open Issues" href="http://issues.apache.org/jira/browse/DIRLDAP"/>
-      <item name="Source Repositories" href="http://svn.apache.org/viewcvs.cgi/directory/shared/ldap/trunk/?root=Apache-SVN"/>
-    </menu>
-
-    <menu name="ApacheCon Europe 2005"> 	 
-      <item name="ApacheCon Europe 2005" href="http://www.apachecon.com/"
-            img="http://apache.org/images/ac2005eu_135x50.gif" />
-    </menu>
- </body>
-
-</project>
diff --git a/pom.xml b/pom.xml
index 07f592a..69ed577 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
     <groupId>org.apache.directory.project</groupId>
     <artifactId>project</artifactId>
     <version>20</version>
-    <relativePath />
+    <relativePath/>
   </parent>
 
   <groupId>org.apache.directory.shared</groupId>
@@ -51,10 +51,14 @@
     <junit.version>4.8.2</junit.version>
     <log4j.version>1.2.16</log4j.version>
     <mina.core.version>2.0.2</mina.core.version>
+    <org.osgi.version>3.0.0</org.osgi.version>
+    <org.osgi.core.version>4.2.0</org.osgi.core.version>
+    <org.apache.felix.version>3.0.2</org.apache.felix.version>
     <slf4j.api.version>1.6.1</slf4j.api.version>
     <slf4j.log4j12.version>1.6.1</slf4j.log4j12.version>
     <xml.apis.version>2.0.2</xml.apis.version>
     <xpp3.version>1.1.4c</xpp3.version>
+    <pax-exam.version>1.2.3</pax-exam.version>
     <findbugs.annotations.version>1.0.0</findbugs.annotations.version>
   </properties>
   
@@ -77,8 +81,9 @@
     <module>asn1-ber</module>
     <module>integ</module>
     <module>all</module>
-    <module>ldap</module>
+    <module>ldap-extras</module>
     <module>ldap-codec</module>
+    <module>ldap-codec-standalone</module>
     <module>ldap-model</module>
     <module>ldap-schema</module>
     <module>ldap-schema-converter</module>
@@ -398,12 +403,6 @@
 
       <dependency>
         <groupId>${project.groupId}</groupId>
-        <artifactId>shared-ldap</artifactId>
-        <version>${project.version}</version>
-      </dependency>
-
-      <dependency>
-        <groupId>${project.groupId}</groupId>
         <artifactId>shared-ldap-model</artifactId>
         <version>${project.version}</version>
       </dependency>
@@ -416,6 +415,36 @@
 
       <dependency>
         <groupId>${project.groupId}</groupId>
+        <artifactId>shared-ldap-codec-standalone</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>shared-ldap-extras-codec</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>shared-ldap-extras-aci</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>shared-ldap-extras-trigger</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>${project.groupId}</groupId>
+        <artifactId>shared-ldap-extras-util</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+        <groupId>${project.groupId}</groupId>
         <artifactId>ldap-client-api</artifactId>
         <version>${project.version}</version>
       </dependency>
@@ -465,7 +494,27 @@
         <artifactId>commons-pool</artifactId>
         <version>${commons.pool.version}</version>
       </dependency>
-      
+
+      <!-- OSGi and Felix Dependencies -->
+
+      <dependency>
+        <groupId>org.osgi</groupId>
+        <artifactId>org.osgi</artifactId>
+        <version>${org.osgi.version}</version>
+      </dependency>
+
+      <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>
@@ -474,6 +523,27 @@
         <version>${org.apache.directory.junit.junit-addons.version}</version>
       </dependency>
 
+      <dependency>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>pax-exam</artifactId>
+        <version>${pax-exam.version}</version>
+        <scope>test</scope>
+      </dependency>
+      
+      <dependency>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>pax-exam-junit</artifactId>
+        <version>${pax-exam.version}</version>
+        <scope>test</scope>
+      </dependency>
+
+      <dependency>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>pax-exam-container-default</artifactId>
+        <version>${pax-exam.version}</version>
+        <scope>test</scope>
+      </dependency>
+
       <!-- Logging dependencies -->
 
       <dependency>
diff --git a/util/src/main/java/org/apache/directory/shared/util/Strings.java b/util/src/main/java/org/apache/directory/shared/util/Strings.java
index c275907..c88a4f2 100644
--- a/util/src/main/java/org/apache/directory/shared/util/Strings.java
+++ b/util/src/main/java/org/apache/directory/shared/util/Strings.java
@@ -6,22 +6,23 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- *  
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- *  
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
- *  under the License. 
- *  
+ *  under the License.
+ *
  */
 package org.apache.directory.shared.util;
 
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import static org.apache.directory.shared.util.Chars.isHex;
+import static org.apache.directory.shared.util.Hex.encodeHex;
+import static org.apache.directory.shared.util.Hex.getHexValue;
 
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStreamWriter;
@@ -33,15 +34,14 @@
 import java.util.Map;
 import java.util.Set;
 
-import static org.apache.directory.shared.util.Chars.isHex;
-import static org.apache.directory.shared.util.Hex.encodeHex;
-import static org.apache.directory.shared.util.Hex.getHexValue;
+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
@@ -51,7 +51,7 @@
 
     /** 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[]
@@ -175,11 +175,11 @@
 
         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
      */
@@ -192,7 +192,7 @@
 
     /**
      * Helper function that returns a char from an hex
-     * 
+     *
      * @param hex The hex to dump
      * @return A char representation of the hex
      */
@@ -203,9 +203,9 @@
 
 
     /**
-     * Helper function that dump an array of bytes in hex pair form, 
+     * 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
      */
@@ -215,27 +215,27 @@
         {
             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 )
@@ -244,24 +244,24 @@
         {
             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 ) )
             {
@@ -275,7 +275,7 @@
                 else
                 {
                     wsSeen = true;
-    
+
                     if ( isStart )
                     {
                         isStart = false;
@@ -294,7 +294,7 @@
                 newbuf[pos++] = ch;
             }
         }
-    
+
         return ( pos == 0 ? "" : new String( newbuf, 0, ( wsSeen ? pos - 1 : pos ) ) );
     }
 
@@ -304,7 +304,7 @@
      * 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 )
@@ -319,7 +319,7 @@
      * non-whitespace characters. A deep trim reduces internal whitespace down
      * to a single space to perserve the whitespace separated tokenization order
      * of the String.
-     * 
+     *
      * @param string the string to deep trim.
      * @return the trimmed string.
      */
@@ -331,7 +331,7 @@
 
     /**
      * 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
@@ -342,16 +342,16 @@
         {
             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 )
@@ -370,17 +370,17 @@
                 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
@@ -389,7 +389,7 @@
     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.
@@ -397,7 +397,7 @@
         {
             return str;
         }
-    
+
         buf = new StringBuffer();
         buf.append( '[' ).append( str.length() ).append( "][" );
         buf.append( str.substring( 0, head ) ).append( "..." );
@@ -405,36 +405,37 @@
         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.
      */
@@ -442,22 +443,22 @@
     {
         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
@@ -470,11 +471,11 @@
     {
         StringBuffer buf = new StringBuffer();
         int len = source.length();
-    
+
         for ( int ii = 0; ii < len; ii++ )
         {
             char ch = source.charAt( ii );
-            
+
             switch ( ch )
             {
                 case '\"':
@@ -487,7 +488,7 @@
                         buf.append( ch );
                     }
                     break;
-    
+
                 case '<':
                     if ( replaceTag )
                     {
@@ -498,7 +499,7 @@
                         buf.append( ch );
                     }
                     break;
-    
+
                 case '>':
                     if ( replaceTag )
                     {
@@ -509,7 +510,7 @@
                         buf.append( ch );
                     }
                     break;
-    
+
                 case '\n':
                     if ( replaceNl )
                     {
@@ -527,27 +528,27 @@
                         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
@@ -555,14 +556,14 @@
      */
     public static boolean areEquals( String string, int index, String text )
     {
-        if ( ( string == null ) || ( text == null ) ) 
+        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 ) ) )
         {
@@ -573,13 +574,13 @@
             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
@@ -600,7 +601,7 @@
 
     /**
      * 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
@@ -612,9 +613,9 @@
         {
             return false;
         }
-        
+
         int length = string.length();
-        
+
         if ( ( length == 0 ) || ( index < 0 ) || ( index >= length ) )
         {
             return false;
@@ -846,7 +847,7 @@
      */
     public static boolean isEmpty( String str )
     {
-        return str == null || str.length() == 0;
+        return ( str == null ) || ( str.length() == 0 );
     }
 
 
@@ -858,7 +859,7 @@
      */
     public static boolean isEmpty( byte[] bytes )
     {
-        return bytes == null || bytes.length == 0;
+        return ( bytes == null ) || ( bytes.length == 0 );
     }
 
 
@@ -1839,7 +1840,7 @@
      */
     public static boolean isNotEmpty( String str )
     {
-        return str != null && str.length() > 0;
+        return ( str != null ) && ( str.length() > 0 );
     }
 
 
@@ -1889,13 +1890,13 @@
 
         if ( isHex( b[0] ) && isHex( b[1] ) && isHex( b[2] ) && isHex( b[3] )
             && isHex( b[4] ) && isHex( b[5] ) && isHex( b[6] ) && isHex( b[7] )
-            && b[8] == '-'
+            && ( b[8] == '-' )
             && isHex( b[9] ) && isHex( b[10] ) && isHex( b[11] ) && isHex( b[12] )
-            && b[13] == '-'
+            && ( b[13] == '-' )
             && isHex( b[14] ) && isHex( b[15] ) && isHex( b[16] ) && isHex( b[17] )
-            && b[18] == '-'
+            && ( b[18] == '-' )
             && isHex( b[19] ) && isHex( b[20] ) && isHex( b[21] ) && isHex( b[22] )
-            && b[23] == '-'
+            && ( b[23] == '-' )
             && isHex( b[24] ) && isHex( b[25] ) && isHex( b[26] ) && isHex( b[27] )
             && isHex( b[28] ) && isHex( b[29] ) && isHex( b[30] ) && isHex( b[31] )
             && isHex( b[32] ) && isHex( b[33] ) && isHex( b[34] ) && isHex( b[35] ) )
@@ -1918,7 +1919,7 @@
      */
     public static String uuidToString( byte[] bytes )
     {
-        if ( bytes == null || bytes.length != 16 )
+        if ( ( bytes == null ) || ( bytes.length != 16 ) )
         {
             return "Invalid UUID";
         }
@@ -1977,11 +1978,11 @@
 
         return bytes;
     }
-    
-    
+
+
     /**
      * Copy a byte array into a new byte array
-     * 
+     *
      * @param value the byte array to copy
      * @return The copied byte array
      */
@@ -1991,10 +1992,10 @@
     	{
     		return StringConstants.EMPTY_BYTES;
     	}
-    	
+
     	byte[] copy = new byte[value.length];
     	System.arraycopy( value, 0, copy, 0, value.length );
-    	
+
     	return copy;
     }
 }