directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject [directory-ldap-api] branch master updated: o Added the EndTransactionResponse implementation o Fixed some I28n name (adding some text after the error number)
Date Thu, 01 Feb 2018 21:49:59 GMT
This is an automated email from the ASF dual-hosted git repository.

elecharny pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/directory-ldap-api.git


The following commit(s) were added to refs/heads/master by this push:
     new eed35a5  o Added the EndTransactionResponse implementation o Fixed some I28n name (adding some text after the error number)
eed35a5 is described below

commit eed35a509543563524b9ce44ae2f615af7edf1f5
Author: Emmanuel L├ęcharny <elecharny@symas.com>
AuthorDate: Thu Feb 1 22:49:47 2018 +0100

    o Added the EndTransactionResponse implementation
    o Fixed some I28n name (adding some text after the error number)
---
 .../java/org/apache/directory/api/i18n/I18n.java   |  11 +-
 .../apache/directory/api/i18n/errors.properties    |  11 +-
 .../api/ldap/codec/actions/CheckLengthNotNull.java |   2 +-
 .../ldap/codec/actions/controls/AddControl.java    |   9 +-
 .../actions/controls/StoreControlCriticality.java  |   8 +-
 .../directory/api/ldap/codec/api/LdapEncoder.java  |   4 +-
 .../endTransaction/EndTransactionResponse.java     |   9 +-
 .../endTransaction/EndTransactionResponseImpl.java |   4 +-
 .../extended/endTransaction/UpdateControls.java    |   4 +-
 .../EndTransactionRequestContainer.java            |   2 +-
 .../EndTransactionRequestGrammar.java              |  42 +--
 ...sEnum.java => EndTransactionRequestStates.java} |   4 +-
 .../EndTransactionResponseContainer.java           | 113 +++++++
 .../EndTransactionResponseDecoder.java             |  60 ++++
 .../EndTransactionResponseDecorator.java           | 247 ++++++++++++++-
 .../EndTransactionResponseGrammar.java             | 330 +++++++++++++++++++++
 ...Enum.java => EndTransactionResponseStates.java} |  29 +-
 .../endTransaction/controls/ControlsContainer.java | 104 +++++++
 .../endTransaction/controls/ControlsGrammar.java   | 219 ++++++++++++++
 .../ControlsStates.java}                           |  29 +-
 .../controls/actions}/AddControl.java              |  30 +-
 .../controls/actions}/StoreControlCriticality.java |  19 +-
 .../controls/actions/StoreControlValue.java        |  94 ++++++
 .../endTransaction/EndTransactionResponseTest.java | 262 ++++++++++++++++
 24 files changed, 1541 insertions(+), 105 deletions(-)

diff --git a/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java b/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java
index e9f31bd..2697950 100644
--- a/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java
+++ b/i18n/src/main/java/org/apache/directory/api/i18n/I18n.java
@@ -234,11 +234,11 @@ public enum I18n
     ERR_04093("ERR_04093"),
     ERR_04094("ERR_04094"),
     ERR_04095("ERR_04095"),
-    ERR_04096("ERR_04096"),
-    ERR_04097("ERR_04097"),
-    ERR_04098("ERR_04098"),
-    ERR_04099("ERR_04099"),
-    ERR_04100("ERR_04100"),
+    ERR_04096_NULL_CONTROL_LENGTH("ERR_04096_NULL_CONTROL_LENGTH"),
+    ERR_04097_NULL_CONTROL_OID("ERR_04097_NULL_CONTROL_OID"),
+    ERR_04098_INVALID_CONTROL_OID("ERR_04098_INVALID_CONTROL_OID"),
+    ERR_04099_INVALID_CONTROL_LIST("ERR_04099_INVALID_CONTROL_LIST"),
+    ERR_04100_BAD_CONTROL_CRITICALITY("ERR_04100_BAD_CONTROL_CRITICALITY"),
     ERR_04101("ERR_04101"),
     ERR_04102("ERR_04102"),
     ERR_04103("ERR_04103"),
@@ -629,6 +629,7 @@ public enum I18n
     ERR_04488_NULL_ATTRIBUTE_TYPE("ERR_04488_NULL_ATTRIBUTE_TYPE"),
     ERR_04489_SYNTAX_INVALID("ERR_04489_SYNTAX_INVALID"),
     ERR_04490_BAD_END_TRANSACTION_COMMIT("ERR_04490_BAD_END_TRANSACTION_COMMIT"),
+    ERR_04491_BAD_END_TRANSACTION_MESSAGE_ID("ERR_04490_BAD_END_TRANSACTION_MESSAGE_ID"),
 
     // ldap-constants
     ERR_05001_UNKNOWN_AUTHENT_LEVEL("ERR_05001_UNKNOWN_AUTHENT_LEVEL"),
diff --git a/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties b/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties
index c4df656..c3f1ae4 100644
--- a/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties
+++ b/i18n/src/main/resources/org/apache/directory/api/i18n/errors.properties
@@ -221,11 +221,11 @@ ERR_04092=The new superior must not be null if the flag ''delete old DN'' is set
 ERR_04093=The attribute description must not be null
 ERR_04094=The CompareResponse must not be null
 ERR_04095=The name must not be null
-ERR_04096=The length of a control must not be null
-ERR_04097=The OID must not be null
-ERR_04098=The control type {0} is not a valid OID
-ERR_04099=Invalid control OID : {0}
-ERR_04100=The control criticality flag {0} is invalid : {1}. It should be 0 or 255
+ERR_04096_NULL_CONTROL_LENGTH=The length of a control must not be null
+ERR_04097_NULL_CONTROL_OID=The OID must not be null
+ERR_04098_INVALID_CONTROL_OID=The control type {0} is not a valid OID
+ERR_04099_INVALID_CONTROL_LIST=Invalid control list {0} : {1}
+ERR_04100_BAD_CONTROL_CRITICALITY=The control criticality flag {0} is invalid : {1}. It should be 0 or 255
 ERR_04101=The scope is not in [0..2] : {0}
 ERR_04102=The derefAlias is not in [0..3] : {0}
 ERR_04103=The sizeLimit is not a valid Integer: {0}
@@ -616,6 +616,7 @@ ERR_04487_ATTRIBUTE_IS_SINGLE_VALUED=The attribute ''{0}'' is single valued, we
 ERR_04488_NULL_ATTRIBUTE_TYPE=The AttributeType cannot be null
 ERR_04489_SYNTAX_INVALID=Syntax invalid for ''{0}''
 ERR_04490_BAD_END_TRANSACTION_COMMIT=The EndTransactionRequest Commit value {0} is invalid: {1}. It should be 0 or 255
+ERR_04490_BAD_END_TRANSACTION_MESSAGE_ID=The endTransactionResponse UpdateControl MessageID value {0} is invalid: {1}. It should be a numeric value
 
 # ldap-constants
 ERR_05001_UNKNOWN_AUTHENT_LEVEL=Unknown AuthenticationLevel {0}
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/CheckLengthNotNull.java b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/CheckLengthNotNull.java
index 1fdc2f3..ed23577 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/CheckLengthNotNull.java
+++ b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/CheckLengthNotNull.java
@@ -62,7 +62,7 @@ public class CheckLengthNotNull extends GrammarAction<LdapMessageContainer<Messa
         // The Length should be null
         if ( expectedLength == 0 )
         {
-            String msg = I18n.err( I18n.ERR_04096 );
+            String msg = I18n.err( I18n.ERR_04096_NULL_CONTROL_LENGTH );
             LOG.error( msg );
 
             // This will generate a PROTOCOL_ERROR
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java
index d9f0a99..4a89e2a 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java
+++ b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java
@@ -73,7 +73,7 @@ public class AddControl extends GrammarAction<LdapMessageContainer<MessageDecora
         // We have to handle the special case of a 0 length OID
         if ( tlv.getLength() == 0 )
         {
-            String msg = I18n.err( I18n.ERR_04097 );
+            String msg = I18n.err( I18n.ERR_04097_NULL_CONTROL_OID );
             LOG.error( msg );
 
             // This will generate a PROTOCOL_ERROR
@@ -86,10 +86,11 @@ public class AddControl extends GrammarAction<LdapMessageContainer<MessageDecora
         // 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 ) ) );
+            String msg = I18n.err( I18n.ERR_04098_INVALID_CONTROL_OID, oidValue );
+            LOG.error( msg );
 
             // This will generate a PROTOCOL_ERROR
-            throw new DecoderException( I18n.err( I18n.ERR_04099, oidValue ) );
+            throw new DecoderException( msg );
         }
 
         Message message = container.getMessage();
@@ -103,7 +104,7 @@ public class AddControl extends GrammarAction<LdapMessageContainer<MessageDecora
 
         if ( IS_DEBUG )
         {
-            LOG.debug( "Control OID : " + oidValue );
+            LOG.debug( "Control OID : {}", oidValue );
         }
     }
 }
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java
index c221fe0..582434a 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java
+++ b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java
@@ -73,10 +73,8 @@ public class StoreControlCriticality extends GrammarAction<LdapMessageContainer<
         TLV tlv = container.getCurrentTLV();
 
         // Get the current control
-        Control control;
-
         MessageDecorator<? extends Message> message = container.getMessage();
-        control = message.getCurrentControl();
+        Control control = message.getCurrentControl();
 
         // Store the criticality
         // We get the value. If it's a 0, it's a FALSE. If it's
@@ -94,7 +92,7 @@ public class StoreControlCriticality extends GrammarAction<LdapMessageContainer<
         catch ( BooleanDecoderException bde )
         {
             LOG.error( I18n
-                .err( I18n.ERR_04100, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
+                .err( I18n.ERR_04100_BAD_CONTROL_CRITICALITY, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
 
             // This will generate a PROTOCOL_ERROR
             throw new DecoderException( bde.getMessage(), bde );
@@ -105,7 +103,7 @@ public class StoreControlCriticality extends GrammarAction<LdapMessageContainer<
 
         if ( IS_DEBUG )
         {
-            LOG.debug( "Control criticality : " + control.isCritical() );
+            LOG.debug( "Control criticality : {}", control.isCritical() );
         }
     }
 }
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapEncoder.java b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapEncoder.java
index da795c0..911a545 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapEncoder.java
+++ b/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/api/LdapEncoder.java
@@ -67,7 +67,7 @@ public class LdapEncoder
     /**
      * Compute the control's encoded length
      */
-    private int computeControlLength( Control control )
+    public static int computeControlLength( Control control )
     {
         // First, compute the control's value length
         int controlValueLength = ( ( CodecControl<?> ) control ).computeLength();
@@ -96,7 +96,7 @@ public class LdapEncoder
     /**
      * Encode a control to a byte[]
      */
-    private ByteBuffer encodeControl( ByteBuffer buffer, Control control ) throws EncoderException
+    public static ByteBuffer encodeControl( ByteBuffer buffer, Control control ) throws EncoderException
     {
         if ( buffer == null )
         {
diff --git a/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/EndTransactionResponse.java b/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/EndTransactionResponse.java
index eac3f1f..4b92a89 100644
--- a/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/EndTransactionResponse.java
+++ b/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/EndTransactionResponse.java
@@ -59,10 +59,17 @@ public interface EndTransactionResponse extends ExtendedResponse
     
     
     /**
-     * @return The Message ID if failire
+     * @return The Message ID if failure
      */
     int getFailedMessageId();
     
+    
+    /**
+     * @param failedMessageId The messageId that causes the failure
+     */
+    void setFailedMessageId( int failedMessageId );
+    
+    
     /**
      * @return the list of <messageId, Controls> processed within the transaction 
      */
diff --git a/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/EndTransactionResponseImpl.java b/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/EndTransactionResponseImpl.java
index a0efe68..e3a5fa1 100644
--- a/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/EndTransactionResponseImpl.java
+++ b/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/EndTransactionResponseImpl.java
@@ -57,7 +57,7 @@ import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
 public class EndTransactionResponseImpl extends ExtendedResponseImpl implements EndTransactionResponse
 {
     /** The faulty Message ID, if any */
-    private int failedMessageId;
+    private int failedMessageId = -1;
     
     /** The list of update controls for the message processed in the transaction */
     private List<UpdateControls> updateControls = new ArrayList<>();
@@ -137,6 +137,7 @@ public class EndTransactionResponseImpl extends ExtendedResponseImpl implements
     /**
      * {@inheritDoc}
      */
+    @Override
     public void setFailedMessageId( int failedMessageId )
     {
         this.failedMessageId = failedMessageId;
@@ -145,6 +146,7 @@ public class EndTransactionResponseImpl extends ExtendedResponseImpl implements
     /**
      * @return the updateControls
      */
+    @Override
     public List<UpdateControls> getUpdateControls()
     {
         return updateControls;
diff --git a/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/UpdateControls.java b/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/UpdateControls.java
index 6962ef9..46c23df 100644
--- a/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/UpdateControls.java
+++ b/ldap/extras/codec-api/src/main/java/org/apache/directory/api/ldap/extras/extended/endTransaction/UpdateControls.java
@@ -22,7 +22,7 @@ package org.apache.directory.api.ldap.extras.extended.endTransaction;
 import java.util.ArrayList;
 import java.util.List;
 
-import javax.naming.ldap.Control;
+import org.apache.directory.api.ldap.model.message.Control;
 
 /**
  * The interface for End Transaction Extended Response UpdateControl. It's described in RFC 5805 :
@@ -180,7 +180,7 @@ public class UpdateControls
                     sb.append( ", " );
                 }
                 
-                sb.append( control.getID() );
+                sb.append( control.getOid() );
             }
             
             sb.append( ']' );
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestContainer.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestContainer.java
index 14b48cf..573a048 100644
--- a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestContainer.java
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestContainer.java
@@ -42,7 +42,7 @@ public class EndTransactionRequestContainer extends AbstractContainer
     {
         super();
         setGrammar( EndTransactionRequestGrammar.getInstance() );
-        setTransition( EndTransactionRequestStatesEnum.START_STATE );
+        setTransition( EndTransactionRequestStates.START_STATE );
     }
 
 
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestGrammar.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestGrammar.java
index f012f10..610e8d5 100644
--- a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestGrammar.java
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestGrammar.java
@@ -28,7 +28,6 @@ import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
 import org.apache.directory.api.asn1.ber.tlv.BerValue;
 import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
 import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
-import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
 import org.apache.directory.api.i18n.I18n;
 import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
 import org.apache.directory.api.ldap.extras.extended.endTransaction.EndTransactionRequestImpl;
@@ -36,6 +35,9 @@ import org.apache.directory.api.util.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.BOOLEAN;
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.OCTET_STRING;
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.SEQUENCE;
 
 /**
  * This class implements the EndTransactionRequest extended operation's ASN.1 grammar. 
@@ -73,7 +75,7 @@ public class EndTransactionRequestGrammar extends AbstractGrammar<EndTransaction
         setName( EndTransactionRequestGrammar.class.getName() );
 
         // Create the transitions table
-        super.transitions = new GrammarTransition[EndTransactionRequestStatesEnum.LAST_STATE
+        super.transitions = new GrammarTransition[EndTransactionRequestStates.LAST_STATE
             .ordinal()][256];
 
         /**
@@ -84,11 +86,11 @@ public class EndTransactionRequestGrammar extends AbstractGrammar<EndTransaction
          *     
          * Creates the EndTransactionRequest object
          */
-        super.transitions[EndTransactionRequestStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
+        super.transitions[EndTransactionRequestStates.START_STATE.ordinal()][SEQUENCE.getValue()] =
             new GrammarTransition<EndTransactionRequestContainer>(
-                EndTransactionRequestStatesEnum.START_STATE,
-                EndTransactionRequestStatesEnum.SEQUENCE_STATE,
-                UniversalTag.SEQUENCE.getValue(), 
+                EndTransactionRequestStates.START_STATE,
+                EndTransactionRequestStates.SEQUENCE_STATE,
+                SEQUENCE, 
                 new GrammarAction<EndTransactionRequestContainer>( "Init EndTransactionRequest" )
                 {
                     public void action( EndTransactionRequestContainer container )
@@ -108,11 +110,11 @@ public class EndTransactionRequestGrammar extends AbstractGrammar<EndTransaction
          *     
          * Set the commit flag into the EndTransactionRequest instance.
          */
-        super.transitions[EndTransactionRequestStatesEnum.SEQUENCE_STATE.ordinal()][UniversalTag.BOOLEAN.getValue()] =
+        super.transitions[EndTransactionRequestStates.SEQUENCE_STATE.ordinal()][BOOLEAN.getValue()] =
             new GrammarTransition<EndTransactionRequestContainer>(
-                EndTransactionRequestStatesEnum.SEQUENCE_STATE,
-                EndTransactionRequestStatesEnum.COMMIT_STATE,
-                UniversalTag.BOOLEAN.getValue(),
+                EndTransactionRequestStates.SEQUENCE_STATE,
+                EndTransactionRequestStates.COMMIT_STATE,
+                BOOLEAN,
                 new GrammarAction<EndTransactionRequestContainer>( "Set EndTransactionRequest commit flag" )
                 {
                     public void action( EndTransactionRequestContainer container ) throws DecoderException
@@ -142,14 +144,14 @@ public class EndTransactionRequestGrammar extends AbstractGrammar<EndTransaction
          *     
          * Set the commit flag into the EndTransactionRequest instance.
          */
-        super.transitions[EndTransactionRequestStatesEnum.SEQUENCE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+        super.transitions[EndTransactionRequestStates.SEQUENCE_STATE.ordinal()][OCTET_STRING.getValue()] =
             new GrammarTransition<EndTransactionRequestContainer>(
-                EndTransactionRequestStatesEnum.SEQUENCE_STATE,
-                EndTransactionRequestStatesEnum.IDENTFIER_STATE,
-                UniversalTag.OCTET_STRING.getValue(),
+                EndTransactionRequestStates.SEQUENCE_STATE,
+                EndTransactionRequestStates.IDENTFIER_STATE,
+                OCTET_STRING,
                 new GrammarAction<EndTransactionRequestContainer>( "Set EndTransactionRequest identifier" )
                 {
-                    public void action( EndTransactionRequestContainer container ) throws DecoderException
+                    public void action( EndTransactionRequestContainer container )
                     {
                         BerValue value = container.getCurrentTLV().getValue();
 
@@ -181,14 +183,14 @@ public class EndTransactionRequestGrammar extends AbstractGrammar<EndTransaction
          *     
          * Set the identifier into the EndTransactionRequest instance.
          */
-        super.transitions[EndTransactionRequestStatesEnum.COMMIT_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
+        super.transitions[EndTransactionRequestStates.COMMIT_STATE.ordinal()][OCTET_STRING.getValue()] =
             new GrammarTransition<EndTransactionRequestContainer>(
-                EndTransactionRequestStatesEnum.COMMIT_STATE,
-                EndTransactionRequestStatesEnum.IDENTFIER_STATE,
-                UniversalTag.OCTET_STRING.getValue(),
+                EndTransactionRequestStates.COMMIT_STATE,
+                EndTransactionRequestStates.IDENTFIER_STATE,
+                OCTET_STRING,
                 new GrammarAction<EndTransactionRequestContainer>( "Set EndTransactionRequest identifier" )
                 {
-                    public void action( EndTransactionRequestContainer container ) throws DecoderException
+                    public void action( EndTransactionRequestContainer container )
                     {
                         BerValue value = container.getCurrentTLV().getValue();
 
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStatesEnum.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStates.java
similarity index 94%
copy from ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStatesEnum.java
copy to ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStates.java
index 9fc8b5f..8c42f64 100644
--- a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStatesEnum.java
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStates.java
@@ -29,7 +29,7 @@ import org.apache.directory.api.asn1.ber.grammar.States;
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public enum EndTransactionRequestStatesEnum implements States
+public enum EndTransactionRequestStates implements States
 {
     /** The END_STATE */
     END_STATE,
@@ -87,7 +87,7 @@ public enum EndTransactionRequestStatesEnum implements States
      * {@inheritDoc}
      */
     @Override
-    public EndTransactionRequestStatesEnum getStartState()
+    public EndTransactionRequestStates getStartState()
     {
         return START_STATE;
     }
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseContainer.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseContainer.java
new file mode 100644
index 0000000..6b13145
--- /dev/null
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseContainer.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction;
+
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.ControlsContainer;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.ControlsStates;
+import org.apache.directory.api.ldap.model.message.Control;
+
+
+/**
+ * A container for EndTransactionResponse codec.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EndTransactionResponseContainer extends AbstractContainer
+{
+    /** EndTransactionResponse decorator*/
+    private EndTransactionResponseDecorator endTransactionResponse;
+    
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+    /**
+     * Creates a new EndTransactionResponseContainer object. We will store one
+     * grammar, it's enough ...
+     */
+    public EndTransactionResponseContainer()
+    {
+        super();
+        setGrammar( EndTransactionResponseGrammar.getInstance() );
+        setTransition( EndTransactionResponseStates.START_STATE );
+    }
+
+
+    /**
+     * @return Returns the EndTransactionResponse instance.
+     */
+    public EndTransactionResponseDecorator getEndTransactionResponse()
+    {
+        return endTransactionResponse;
+    }
+
+
+    /**
+     * Set a EndTransactionResponse Object into the container. It will be completed by
+     * the ldapDecoder.
+     * 
+     * @param endTransactionResponseDecorator the EndTransactionResponse to set.
+     */
+    public void setEndTransactionResponse( EndTransactionResponseDecorator endTransactionResponseDecorator )
+    {
+        this.endTransactionResponse = endTransactionResponseDecorator;
+    }
+
+
+    /**
+     * Clean the container for the next decoding.
+     */
+    @Override
+    public void clean()
+    {
+        super.clean();
+        endTransactionResponse = null;
+    }
+    
+    
+    /**
+     * Decodes raw ASN.1 encoded bytes into an Asn1Object for the controls.
+     * 
+     * @param controlsBytes the encoded controls bytes
+     * @return the decoded controls
+     * @throws DecoderException if anything goes wrong
+     */
+    public static List<Control> decode( byte[] controlsBytes ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( controlsBytes );
+        ControlsContainer container = new ControlsContainer();
+        
+        // Loop on all the contained controls
+        while ( bb.hasRemaining() )
+        {
+            DECODER.decode( bb, container );
+            container.setState( TLVStateEnum.TAG_STATE_START );
+            container.setTransition( ControlsStates.START_STATE );
+        }
+        
+        return container.getControls();
+    }
+}
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseDecoder.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseDecoder.java
new file mode 100644
index 0000000..75a8189
--- /dev/null
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseDecoder.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction;
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.extras.extended.endTransaction.EndTransactionResponse;
+
+
+/**
+ * A decoder for EndTransactionResponse.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EndTransactionResponseDecoder extends Asn1Decoder
+{
+    /** The decoder */
+    private static final Asn1Decoder DECODER = new Asn1Decoder();
+
+    /**
+     * Decode a PDU which must contain a EndTransactionResponse extended operation.
+     * Note that the stream of bytes much contain a full PDU, not a partial one.
+     * 
+     * @param stream The bytes to be decoded
+     * @return a EndTransactionResponse object
+     * @throws org.apache.directory.api.asn1.DecoderException If the decoding failed
+     */
+    public EndTransactionResponse decode( byte[] stream ) throws DecoderException
+    {
+        ByteBuffer bb = ByteBuffer.wrap( stream );
+        EndTransactionResponseContainer container = new EndTransactionResponseContainer();
+        DECODER.decode( bb, container );
+        EndTransactionResponseDecorator endTransactionResponse = container.getEndTransactionResponse();
+
+        // Clean the container for the next decoding
+        container.clean();
+
+        return endTransactionResponse;
+    }
+}
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseDecorator.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseDecorator.java
index 0d194c2..e87e4fb 100644
--- a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseDecorator.java
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseDecorator.java
@@ -20,13 +20,24 @@
 package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction;
 
 
+import java.nio.ByteBuffer;
 import java.util.List;
 
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
 import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
 import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.api.LdapEncoder;
 import org.apache.directory.api.ldap.extras.extended.endTransaction.EndTransactionResponse;
 import org.apache.directory.api.ldap.extras.extended.endTransaction.UpdateControls;
-import org.apache.directory.api.util.Strings;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 
 /**
@@ -36,11 +47,28 @@ import org.apache.directory.api.util.Strings;
  */
 public class EndTransactionResponseDecorator extends ExtendedResponseDecorator<EndTransactionResponse> implements EndTransactionResponse
 {
+    private static final Logger LOG = LoggerFactory.getLogger( EndTransactionResponseDecorator.class );
+
     /** The endTransaction response */
     private EndTransactionResponse endTransactionResponse;
 
-    /** stores the length of the request*/
-    private int requestLength = 0;
+    /** The current UpdateControls */
+    private UpdateControls currentUpdateControls;
+
+    /** Stores the length of the request*/
+    private int globalSequenceLength = 0;
+    
+    /** Stores the length of the updateControls part */
+    private int updateSequenceLength = 0;
+    
+    /** Stores the length of updateControls */
+    private int[] updateControlsLength;
+    
+    /** Stores the Controls global lengths */
+    private int[] controlsLengths;
+    
+    /** The message controls' lengths */ 
+    private int[][] controlLengths;
 
     /**
      * Creates a new instance of EndTransactionResponseDecorator.
@@ -61,7 +89,27 @@ public class EndTransactionResponseDecorator extends ExtendedResponseDecorator<E
     @Override
     public void setResponseValue( byte[] responseValue )
     {
-        this.responseValue = Strings.copy( responseValue );
+        EndTransactionResponseDecoder decoder = new EndTransactionResponseDecoder();
+
+        try
+        {
+            if ( responseValue != null )
+            {
+                endTransactionResponse = decoder.decode( responseValue );
+
+                this.responseValue = new byte[responseValue.length];
+                System.arraycopy( responseValue, 0, this.responseValue, 0, responseValue.length );
+            }
+            else
+            {
+                this.responseValue = null;
+            }
+        }
+        catch ( DecoderException e )
+        {
+            LOG.error( I18n.err( I18n.ERR_04165_PAYLOAD_DECODING_ERROR ), e );
+            throw new RuntimeException( e );
+        }
     }
 
 
@@ -75,9 +123,200 @@ public class EndTransactionResponseDecorator extends ExtendedResponseDecorator<E
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setFailedMessageId( int failedMessageId )
+    {
+        endTransactionResponse.setFailedMessageId( failedMessageId );
+    }
+
+
     @Override
     public List<UpdateControls> getUpdateControls()
     {
         return endTransactionResponse.getUpdateControls();
     }
+
+    
+    /**
+     * @return the currentUpdateControls
+     */
+    public UpdateControls getCurrentUpdateControls()
+    {
+        return currentUpdateControls;
+    }
+
+    
+    /**
+     * @param currentUpdateControls the currentUpdateControls to set
+     */
+    public void setCurrentControls( UpdateControls currentUpdateControls )
+    {
+        this.currentUpdateControls = currentUpdateControls;
+    }
+
+
+    /**
+     * Compute the EndTransactionResponse extended operation length
+     * <pre>
+     * 0x30 L1 
+     *   | 
+     *  [+-- 0x02 L2 failed message ID] 
+     *  [+-- 0x30 L3 updateControls SEQUENCE OF
+     *         |
+     *         +-- 0x30 L4 updateControls SEQUENCE
+     *               |
+     *               +-- 0x02 L5 messageID
+     *               +-- <controls>]
+     *               
+     * </pre>
+     */
+    /* No qualifier */int computeLengthInternal()
+    {
+        globalSequenceLength = 0;
+        
+        if ( endTransactionResponse.getFailedMessageId() >= 0 )
+        {
+            // We have had a failure, there is no updateControls just the failed MessageID
+            globalSequenceLength = 1 + 1 + BerValue.getNbBytes( endTransactionResponse.getFailedMessageId() );
+            
+            // The message ID length is always below 128, so we only need 1 byte for the global length
+            return 1 + 1 + globalSequenceLength;
+        }
+        else
+        {
+            // If it's a success, we won't have a messageId, just update controls (if any)
+            int updateControlsSize = getUpdateControls().size();
+            
+            if ( updateControlsSize > 0 )
+            {
+                updateControlsLength = new int[updateControlsSize];
+                controlsLengths = new int[updateControlsSize];
+                controlLengths = new int[updateControlsSize][];
+                int messageControlsCount = 0;
+                updateSequenceLength = 0;
+                
+                // Ok, process the updateControls
+                for ( UpdateControls updateControls : getUpdateControls() )
+                {
+                    // The message ID, 0x02 LL and the ID
+                    updateControlsLength[messageControlsCount] = 1 + 1 + BerValue.getNbBytes( updateControls.getMessageId() );
+                    
+                    // The controls
+                    int controlNumber = updateControls.getControls().size();
+                    
+                    if ( controlNumber > 0 )
+                    { 
+                        int controlCount = 0;
+                        controlLengths[messageControlsCount] = new int[controlNumber];
+                        
+                        for ( Control control : updateControls.getControls() )
+                        {
+                            controlLengths[messageControlsCount][controlCount] = LdapEncoder.computeControlLength( control );
+                            controlsLengths[messageControlsCount] +=  1 + TLV.getNbBytes( controlLengths[messageControlsCount][controlCount] ) + controlLengths[messageControlsCount][controlCount];
+                            controlCount++;
+                        }
+                        
+                        int controlsLength = controlsLengths[messageControlsCount];
+                        updateControlsLength[messageControlsCount] +=  1 + TLV.getNbBytes( controlsLength ) + controlsLength;
+                    }
+                    
+                    updateSequenceLength += 1 + TLV.getNbBytes( updateControlsLength[messageControlsCount] ) 
+                        + updateControlsLength[messageControlsCount];
+
+                    messageControlsCount++;
+                }
+                
+                globalSequenceLength = 1 + TLV.getNbBytes( updateSequenceLength ) + updateSequenceLength;
+                
+                return 1 + TLV.getNbBytes( globalSequenceLength ) + globalSequenceLength;
+            }
+            else
+            {
+                // No update control, return immediately
+                return 0;
+            }
+        }
+    }
+
+
+    /**
+     * Encodes the EndTransactionResponse extended operation.
+     * 
+     * @return A ByteBuffer that contains the encoded PDU
+     * @throws org.apache.directory.api.asn1.EncoderException If anything goes wrong.
+     */
+    /* No qualifier */ByteBuffer encodeInternal() throws EncoderException
+    {
+        ByteBuffer bb = ByteBuffer.allocate( computeLengthInternal() );
+
+        bb.put( UniversalTag.SEQUENCE.getValue() );
+        bb.put( TLV.getBytes( globalSequenceLength ) );
+        
+        // The failed message id, if any
+        if ( getFailedMessageId() >= 0 )
+        {
+            // We have had an error, just encode the messageId
+            BerValue.encode( bb, getFailedMessageId() );
+        }
+        else
+        {
+            // No error, just updateControls
+            bb.put( UniversalTag.SEQUENCE.getValue() );
+            bb.put( TLV.getBytes( updateSequenceLength ) );
+
+            int updateControlsNb = 0;
+            
+            for ( UpdateControls updateControls : getUpdateControls() )
+            {
+                // The updateControls length
+                bb.put( UniversalTag.SEQUENCE.getValue() );
+                bb.put( TLV.getBytes( updateControlsLength[updateControlsNb] ) );
+
+                // The message ID
+                BerValue.encode( bb, updateControls.getMessageId() );
+                
+                // The controls sequence
+                bb.put( UniversalTag.SEQUENCE.getValue() );
+                bb.put( TLV.getBytes( controlsLengths[updateControlsNb] ) );
+                
+                // The controls
+                int controlNb = 0;
+
+                for ( Control control : updateControls.getControls() )
+                {
+                    // The control SEQUENCE
+                    bb.put( UniversalTag.SEQUENCE.getValue() );
+                    bb.put( TLV.getBytes( controlLengths[updateControlsNb][controlNb] ) );
+                    
+                    // The control OID
+                    BerValue.encode( bb, control.getOid() );
+
+                    // The criticality, if true
+                    if ( control.isCritical() )
+                    {
+                        BerValue.encode( bb,  true );
+                    }
+                    
+                    // compute the value length 
+                    int valueLength = ( ( CodecControl<?> ) control ).computeLength();
+                    
+                    if ( valueLength > 0 )
+                    {
+                        bb.put( UniversalTag.OCTET_STRING.getValue() );
+                        bb.put( TLV.getBytes( valueLength ) );
+                        ( ( CodecControl<?> ) control ).encode( bb );
+                    }
+                    
+                    controlNb++;
+                }
+                
+                updateControlsNb++;
+            }
+        }
+
+        return bb;
+    }
 }
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseGrammar.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseGrammar.java
new file mode 100644
index 0000000..1a570f0
--- /dev/null
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseGrammar.java
@@ -0,0 +1,330 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction;
+
+
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.SEQUENCE;
+
+import java.util.List;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
+import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
+import org.apache.directory.api.ldap.extras.extended.endTransaction.EndTransactionResponseImpl;
+import org.apache.directory.api.ldap.extras.extended.endTransaction.UpdateControls;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.INTEGER;
+
+/**
+ * This class implements the EndTransactionResponse extended operation's ASN.1 grammar. 
+ * All the actions are declared in this class. As it is a singleton, 
+ * these declaration are only done once. The grammar is :
+ * 
+ * <pre>
+ * txnEndRes ::= SEQUENCE {
+ *         messageID MessageID OPTIONAL,
+ *              -- msgid associated with non-success resultCode
+ *         updatesControls SEQUENCE OF updateControl SEQUENCE {
+ *              messageID MessageID,
+ *                   -- msgid associated with controls
+ *              controls  Controls
+ *         } OPTIONAL
+ *    }
+ * </pre>
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EndTransactionResponseGrammar extends AbstractGrammar<EndTransactionResponseContainer>
+{
+    /** logger */
+    private static final Logger LOG = LoggerFactory.getLogger( EndTransactionResponseGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. EndTransactionResponseGrammar is a singleton */
+    private static Grammar<EndTransactionResponseContainer> instance = new EndTransactionResponseGrammar();
+
+
+    /**
+     * Creates a new EndTransactionResponseGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    public EndTransactionResponseGrammar()
+    {
+        setName( EndTransactionResponseGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[EndTransactionResponseStates.LAST_STATE
+            .ordinal()][256];
+
+        /**
+         * Transition from init state to EndTransactionResponse Sequence
+         * 
+         *  txnEndRes ::= SEQUENCE {
+         *     ...
+         *     
+         * Creates the EndTransactionResponse object
+         */
+        super.transitions[EndTransactionResponseStates.START_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<EndTransactionResponseContainer>(
+                EndTransactionResponseStates.START_STATE,
+                EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE,
+                SEQUENCE, 
+                new GrammarAction<EndTransactionResponseContainer>( "Init EndTransactionResponse" )
+                {
+                    public void action( EndTransactionResponseContainer container )
+                    {
+                        // Create the decorator, and stores it in the container
+                        EndTransactionResponseDecorator endTransactionResponseDecorator = new EndTransactionResponseDecorator(
+                            LdapApiServiceFactory.getSingleton(), new EndTransactionResponseImpl() );
+                        container.setEndTransactionResponse( endTransactionResponseDecorator );
+                    }
+                } );
+
+        /**
+         * Transition from Sequence to messageId
+         *
+         * txnEndReq ::= SEQUENCE {
+         *         messageID MessageID OPTIONAL,
+         *              -- msgid associated with non-success resultCode
+         *     ...
+         *     
+         * Set the messageId into the EndTransactionResponse instance, if it's not SUCCESS.
+         */
+        super.transitions[EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE.ordinal()][INTEGER.getValue()] =
+            new GrammarTransition<EndTransactionResponseContainer>(
+                EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE,
+                EndTransactionResponseStates.FAILED_MESSAGE_ID_STATE,
+                INTEGER,
+                new GrammarAction<EndTransactionResponseContainer>( "Set EndTransactionResponse failed MessageID" )
+                {
+                    public void action( EndTransactionResponseContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            int failedMessageId = IntegerDecoder.parse( value );
+                            
+                            if ( failedMessageId > 0 )
+                            {
+                                container.getEndTransactionResponse().setFailedMessageId( failedMessageId );
+                            }
+
+                            // We may have nothing left
+                            container.setGrammarEndAllowed( true );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            LOG.error( I18n
+                                .err( I18n.ERR_04490_BAD_END_TRANSACTION_COMMIT, Strings.dumpBytes( value.getData() ), ide.getMessage() ) );
+
+                            // This will generate a PROTOCOL_ERROR
+                            throw new DecoderException( ide.getMessage(), ide );
+                        }
+                    }
+                } );
+
+        
+        /**
+         * Transition from Sequence to updateControls
+         *
+         * txnEndReq ::= SEQUENCE {
+         *                  ...
+         *                  updatesControls SEQUENCE OF updateControls SEQUENCE {
+         *     
+         * Nothing to do, just transitionning
+         */
+        super.transitions[EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<EndTransactionResponseContainer>(
+                EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE,
+                EndTransactionResponseStates.UPDATE_CONTROLS_SEQ_STATE,
+                SEQUENCE );
+
+        
+        /**
+         * Transition from updateControls to updateControl
+         *
+         * txnEndReq ::= SEQUENCE {
+         *                  ...updateControls SEQUENCE {
+         *     
+         * Create a new UpdateControls instane
+         */
+        super.transitions[EndTransactionResponseStates.UPDATE_CONTROLS_SEQ_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<EndTransactionResponseContainer>(
+                EndTransactionResponseStates.UPDATE_CONTROLS_SEQ_STATE,
+                EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE,
+                SEQUENCE,
+                new GrammarAction<EndTransactionResponseContainer>( "Create an updateControl" )
+                {
+                    public void action( EndTransactionResponseContainer container )
+                    {
+                        // Create the current UpdateControls
+                        UpdateControls currentUpdateControls = new UpdateControls();
+                        
+                        container.getEndTransactionResponse().setCurrentControls( currentUpdateControls );
+                    }
+                } );
+
+        
+        /**
+         * Transition from updateControl to messageId
+         *
+         * txnEndReq ::= SEQUENCE {
+         *                  ...
+         *                  messageID MessageID,
+         *     
+         * Set the messageId into the current updateControl
+         */
+        super.transitions[EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE.ordinal()][INTEGER.getValue()] =
+            new GrammarTransition<EndTransactionResponseContainer>(
+                EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE,
+                EndTransactionResponseStates.CONTROL_MESSAGE_ID_STATE,
+                INTEGER,
+                new GrammarAction<EndTransactionResponseContainer>( "Get the updateControl messageId" )
+                {
+                    public void action( EndTransactionResponseContainer container ) throws DecoderException
+                    {
+                        UpdateControls currentUpdateControls = container.getEndTransactionResponse().getCurrentUpdateControls();
+                        BerValue value = container.getCurrentTLV().getValue();
+
+                        try
+                        {
+                            int messageId = IntegerDecoder.parse( value );
+                            
+                            currentUpdateControls.setMessageId( messageId );
+                            
+                            // Make the container gather the following bytes
+                            container.setGathering( true );
+                        }
+                        catch ( IntegerDecoderException ide )
+                        {
+                            LOG.error( I18n
+                                .err( I18n.ERR_04491_BAD_END_TRANSACTION_MESSAGE_ID, Strings.dumpBytes( value.getData() ), 
+                                    ide.getMessage() ) );
+
+                            // This will generate a PROTOCOL_ERROR
+                            throw new DecoderException( ide.getMessage(), ide );
+                        }
+                    }
+                } );
+        
+        
+        /**
+         * ...
+         *              messageID MessageID,
+         *                   -- msgid associated with controls
+         *              controls  Controls
+         *  ...
+         *
+         * Process the controls
+         */
+        super.transitions[EndTransactionResponseStates.CONTROL_MESSAGE_ID_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<EndTransactionResponseContainer>(
+                EndTransactionResponseStates.CONTROL_MESSAGE_ID_STATE,
+                EndTransactionResponseStates.CONTROLS_STATE,
+                SEQUENCE,
+                new GrammarAction<EndTransactionResponseContainer>( "Process the controls" )
+                {
+                    public void action( EndTransactionResponseContainer container ) throws DecoderException
+                    {
+                        BerValue value = container.getCurrentTLV().getValue();
+                        
+                        container.setGathering( false );
+
+                        try
+                        {
+                            List<Control> controls = EndTransactionResponseContainer.decode( value.getData() );
+                            
+                            // Add the updateControls to the list of updateControls
+                            UpdateControls currentUpdateControls = container.getEndTransactionResponse().getCurrentUpdateControls();
+                            
+                            // Add the decoder controls
+                            currentUpdateControls.setControls( controls );
+                            
+                            // And add the decoded updateControls to the list of updateControls
+                            container.getEndTransactionResponse().getUpdateControls().add( currentUpdateControls );
+                        }
+                        catch ( DecoderException de )
+                        {
+                            // Add an error
+                            LOG.error( I18n
+                                .err( I18n.ERR_04099_INVALID_CONTROL_LIST, Strings.dumpBytes( value.getData() ), 
+                                    de.getMessage() ) );
+
+                            // This will generate a PROTOCOL_ERROR
+                            throw new DecoderException( de.getMessage(), de );
+                        }
+
+                        // We may have nothing left
+                        container.setGrammarEndAllowed( true );
+                    }
+                } );
+
+        
+        /**
+         * Transition from controls to updateControl
+         *
+         * txnEndReq ::= SEQUENCE {
+         *                  ...
+         *                  messageID MessageID,
+         *     
+         * Loop on the updateControl
+         */
+        super.transitions[EndTransactionResponseStates.CONTROLS_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<EndTransactionResponseContainer>(
+                EndTransactionResponseStates.CONTROLS_STATE,
+                EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE,
+                SEQUENCE,
+                new GrammarAction<EndTransactionResponseContainer>( "Get the updateControl messageId" )
+                {
+                    public void action( EndTransactionResponseContainer container )
+                    {
+                        // Create a new current UpdateControl
+                        UpdateControls currentUpdateControls = new UpdateControls();
+                        
+                        container.getEndTransactionResponse().setCurrentControls( currentUpdateControls );
+                    }
+                } );
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<EndTransactionResponseContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStatesEnum.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseStates.java
similarity index 74%
copy from ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStatesEnum.java
copy to ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseStates.java
index 9fc8b5f..7be6e9e 100644
--- a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStatesEnum.java
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseStates.java
@@ -24,12 +24,12 @@ import org.apache.directory.api.asn1.ber.grammar.States;
 
 
 /**
- * This class store the EndTransactionRequest's grammar constants. It is also used
+ * This class store the EndTransactionResponse's grammar constants. It is also used
  * for debugging purposes.
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public enum EndTransactionRequestStatesEnum implements States
+public enum EndTransactionResponseStates implements States
 {
     /** The END_STATE */
     END_STATE,
@@ -38,13 +38,22 @@ public enum EndTransactionRequestStatesEnum implements States
     START_STATE,
     
     /** The initial SEQUENCE */
-    SEQUENCE_STATE,
+    END_TRANSACTION_SEQUENCE_STATE,
     
-    /** The commit flag */
-    COMMIT_STATE,
+    /** The failed message ID */
+    FAILED_MESSAGE_ID_STATE,
     
-    /** The identifier state */
-    IDENTFIER_STATE,
+    /** The update controls SEQ */
+    UPDATE_CONTROLS_SEQ_STATE,
+    
+    /** The update control SEQ */
+    UPDATE_CONTROL_SEQ_STATE,
+    
+    /** THe control's message ID state */
+    CONTROL_MESSAGE_ID_STATE,
+    
+    /** The control's state */
+    CONTROLS_STATE,
 
     /** Last state */
     LAST_STATE;
@@ -57,7 +66,7 @@ public enum EndTransactionRequestStatesEnum implements States
      */
     public String getGrammarName()
     {
-        return "END_TRANSACTION_REQUEST_GRAMMER";
+        return "END_TRANSACTION_RESPONSE_GRAMMER";
     }
 
 
@@ -69,7 +78,7 @@ public enum EndTransactionRequestStatesEnum implements States
      */
     public String getState( int state )
     {
-        return ( state == END_STATE.ordinal() ) ? "END_TRANSACTION_REQUEST_GRAMMER" : name();
+        return ( state == END_STATE.ordinal() ) ? "END_TRANSACTION_RESPONSE_GRAMMER" : name();
     }
 
 
@@ -87,7 +96,7 @@ public enum EndTransactionRequestStatesEnum implements States
      * {@inheritDoc}
      */
     @Override
-    public EndTransactionRequestStatesEnum getStartState()
+    public EndTransactionResponseStates getStartState()
     {
         return START_STATE;
     }
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/ControlsContainer.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/ControlsContainer.java
new file mode 100644
index 0000000..3d9d748
--- /dev/null
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/ControlsContainer.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.directory.api.asn1.ber.AbstractContainer;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.osgi.DefaultLdapCodecService;
+import org.apache.directory.api.ldap.model.message.Control;
+
+/**
+ * A container storing decoded controls for a EndTransactionResponse extended operation
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ControlsContainer extends AbstractContainer
+{
+    /** The list of decoded controls */
+    private List<Control> controls = new ArrayList<>();
+    
+    /** The current control */
+    private CodecControl<?> currentControl;
+
+    /** The codec service */
+    private final LdapApiService codec;
+
+    /**
+     * A constructor for this container
+     */
+    public ControlsContainer()
+    {
+        super();
+        setGrammar( ControlsGrammar.getInstance() );
+        setTransition( ControlsStates.START_STATE );
+        this.codec = new DefaultLdapCodecService();
+    }
+
+
+    /**
+     * Gets the {@link LdapApiService} associated with this Container.
+     *
+     * @return The LDAP service instance
+     */
+    public LdapApiService getLdapCodecService()
+    {
+        return codec;
+    }
+
+    
+    /**
+     * @return the currentControl
+     */
+    public CodecControl<?> getCurrentControl()
+    {
+        return currentControl;
+    }
+
+
+    /**
+     * @param currentControl the currentControl to set
+     */
+    public void setCurrentControl( CodecControl<?> currentControl )
+    {
+        this.currentControl = currentControl;
+    }
+
+
+    /**
+     * @return the controls
+     */
+    public List<Control> getControls()
+    {
+        return controls;
+    }
+    
+
+    /**
+     * @param control the controls to add to the list of controls
+     */
+    public void addControl( Control control )
+    {
+        controls.add( control );
+    }
+}
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/ControlsGrammar.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/ControlsGrammar.java
new file mode 100644
index 0000000..d9e3b2c
--- /dev/null
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/ControlsGrammar.java
@@ -0,0 +1,219 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls;
+
+import org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
+import org.apache.directory.api.asn1.ber.grammar.Grammar;
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.i18n.I18n;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.actions.AddControl;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.actions.StoreControlCriticality;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.actions.StoreControlValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.BOOLEAN;
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.OCTET_STRING;
+import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.SEQUENCE;
+
+/**
+ * A grammar to decode controls in a EndTransactionResponse extended operation
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ControlsGrammar extends AbstractGrammar<ControlsContainer>
+{
+    /** logger */
+    private static final Logger LOG = LoggerFactory.getLogger( ControlsGrammar.class );
+
+    /** Speedup for logs */
+    static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The instance of grammar. ControlsGrammar is a singleton */
+    private static Grammar<ControlsContainer> instance = new ControlsGrammar();
+
+
+    /**
+     * Creates a new ControlsGrammar object.
+     */
+    @SuppressWarnings("unchecked")
+    public ControlsGrammar()
+    {
+        setName( ControlsGrammar.class.getName() );
+
+        // Create the transitions table
+        super.transitions = new GrammarTransition[ControlsStates.LAST_STATE.ordinal()][256];
+
+        /**
+         * Transition from init state to Control Sequence
+         * 
+         *  Control ::= SEQUENCE {
+         *     ...
+         *     
+         * Creates the current control instance
+         */
+        super.transitions[ControlsStates.START_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<ControlsContainer>(
+                ControlsStates.START_STATE,
+                ControlsStates.CONTROL_SEQUENCE_STATE,
+                SEQUENCE, 
+                new GrammarAction<ControlsContainer>( "Init Control" )
+                {
+                    public void action( ControlsContainer 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_NULL_CONTROL_LENGTH );
+                            LOG.error( msg );
+
+                            // This will generate a PROTOCOL_ERROR
+                            throw new DecoderException( msg );
+                        }
+                    }
+                } );
+
+        /**
+         * Transition from controlSequence state to control type
+         * 
+         *  Control ::= SEQUENCE {
+         *     controlType             LDAPOID,
+         *     ...
+         *     
+         * Creates the current control instance
+         */
+        super.transitions[ControlsStates.CONTROL_SEQUENCE_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition<ControlsContainer>(
+                ControlsStates.CONTROL_SEQUENCE_STATE,
+                ControlsStates.CONTROL_TYPE_STATE,
+                OCTET_STRING, 
+                new AddControl() );
+
+        /**
+         * Transition from control type to control criticality
+         * 
+         *  Control ::= SEQUENCE {
+         *     controlType             LDAPOID,
+         *     criticality             BOOLEAN DEFAULT FALSE,
+         *     ...
+         *     
+         * Store the criticality
+         */
+        super.transitions[ControlsStates.CONTROL_TYPE_STATE.ordinal()][BOOLEAN.getValue()] =
+            new GrammarTransition<ControlsContainer>(
+                ControlsStates.CONTROL_TYPE_STATE,
+                ControlsStates.CONTROL_CRITICALITY_STATE,
+                BOOLEAN, 
+                new StoreControlCriticality() );
+
+        /**
+         * Transition from control type to control value
+         * 
+         *  Control ::= SEQUENCE {
+         *     controlType             LDAPOID,
+         *     ...
+         *     controlValue            OCTET STRING OPTIONAL }
+         *     
+         * Store the value
+         */
+        super.transitions[ControlsStates.CONTROL_TYPE_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition<ControlsContainer>(
+                ControlsStates.CONTROL_TYPE_STATE,
+                ControlsStates.CONTROL_VALUE_STATE,
+                OCTET_STRING, 
+                new StoreControlValue() );
+
+        /**
+         * Transition from control type to control sequence
+         * 
+         *  Control ::= SEQUENCE {
+         *     controlType             LDAPOID,
+         *     
+         * Nothing to do
+         */
+        super.transitions[ControlsStates.CONTROL_TYPE_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<ControlsContainer>(
+                ControlsStates.CONTROL_TYPE_STATE,
+                ControlsStates.CONTROL_SEQUENCE_STATE,
+                SEQUENCE );
+        
+        /**
+         * Transition from control criticality to control value
+         * 
+         *  Control ::= SEQUENCE {
+         *     ...
+         *     criticality             BOOLEAN DEFAULT FALSE,
+         *     controlValue            OCTET STRING OPTIONAL }
+         *     
+         * Store the value
+         */
+        super.transitions[ControlsStates.CONTROL_CRITICALITY_STATE.ordinal()][OCTET_STRING.getValue()] =
+            new GrammarTransition<ControlsContainer>(
+                ControlsStates.CONTROL_CRITICALITY_STATE,
+                ControlsStates.CONTROL_VALUE_STATE,
+                OCTET_STRING, 
+                new StoreControlValue() );
+        
+        /**
+         * Transition from control criticality to control sequence
+         * 
+         *  Control ::= SEQUENCE {
+         *     ...
+         *     criticality             BOOLEAN DEFAULT FALSE,
+         *     
+         * Nothing to do
+         */
+        super.transitions[ControlsStates.CONTROL_CRITICALITY_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<ControlsContainer>(
+                ControlsStates.CONTROL_CRITICALITY_STATE,
+                ControlsStates.CONTROL_SEQUENCE_STATE,
+                SEQUENCE );
+
+        /**
+         * Transition from control value to control sequence
+         * 
+         *  Control ::= SEQUENCE {
+         *     
+         * Nothing to do
+         */
+        super.transitions[ControlsStates.CONTROL_VALUE_STATE.ordinal()][SEQUENCE.getValue()] =
+            new GrammarTransition<ControlsContainer>(
+                ControlsStates.CONTROL_VALUE_STATE,
+                ControlsStates.CONTROL_SEQUENCE_STATE,
+                SEQUENCE ); 
+    }
+
+
+    /**
+     * This class is a singleton.
+     * 
+     * @return An instance on this grammar
+     */
+    public static Grammar<ControlsContainer> getInstance()
+    {
+        return instance;
+    }
+}
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStatesEnum.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/ControlsStates.java
similarity index 77%
rename from ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStatesEnum.java
rename to ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/ControlsStates.java
index 9fc8b5f..b0d10fc 100644
--- a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionRequestStatesEnum.java
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/ControlsStates.java
@@ -17,19 +17,17 @@
  *  under the License. 
  *  
  */
-package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction;
-
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls;
 
 import org.apache.directory.api.asn1.ber.grammar.States;
 
-
 /**
- * This class store the EndTransactionRequest's grammar constants. It is also used
+ * This class store the Controls' grammar constants. It is also used
  * for debugging purposes.
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public enum EndTransactionRequestStatesEnum implements States
+public enum ControlsStates implements States
 {
     /** The END_STATE */
     END_STATE,
@@ -37,14 +35,17 @@ public enum EndTransactionRequestStatesEnum implements States
     /** start state*/
     START_STATE,
     
-    /** The initial SEQUENCE */
-    SEQUENCE_STATE,
+    /** The Control SEQUENCE */
+    CONTROL_SEQUENCE_STATE,
+    
+    /** The Control type */
+    CONTROL_TYPE_STATE,
     
-    /** The commit flag */
-    COMMIT_STATE,
+    /** The criticality */
+    CONTROL_CRITICALITY_STATE,
     
-    /** The identifier state */
-    IDENTFIER_STATE,
+    /** The value */
+    CONTROL_VALUE_STATE,
 
     /** Last state */
     LAST_STATE;
@@ -57,7 +58,7 @@ public enum EndTransactionRequestStatesEnum implements States
      */
     public String getGrammarName()
     {
-        return "END_TRANSACTION_REQUEST_GRAMMER";
+        return "CONTROLS_GRAMMAR";
     }
 
 
@@ -69,7 +70,7 @@ public enum EndTransactionRequestStatesEnum implements States
      */
     public String getState( int state )
     {
-        return ( state == END_STATE.ordinal() ) ? "END_TRANSACTION_REQUEST_GRAMMER" : name();
+        return ( state == END_STATE.ordinal() ) ? "CONTROLS_GRAMMER" : name();
     }
 
 
@@ -87,7 +88,7 @@ public enum EndTransactionRequestStatesEnum implements States
      * {@inheritDoc}
      */
     @Override
-    public EndTransactionRequestStatesEnum getStartState()
+    public ControlsStates getStartState()
     {
         return START_STATE;
     }
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/actions/AddControl.java
similarity index 72%
copy from ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java
copy to ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/actions/AddControl.java
index d9f0a99..37c9451 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/AddControl.java
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/actions/AddControl.java
@@ -17,7 +17,7 @@
  *  under the License.
  *
  */
-package org.apache.directory.api.ldap.codec.actions.controls;
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.actions;
 
 
 import org.apache.directory.api.asn1.DecoderException;
@@ -25,10 +25,8 @@ import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
 import org.apache.directory.api.asn1.ber.tlv.TLV;
 import org.apache.directory.api.asn1.util.Oid;
 import org.apache.directory.api.i18n.I18n;
-import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
-import org.apache.directory.api.ldap.codec.api.MessageDecorator;
-import org.apache.directory.api.ldap.model.message.Control;
-import org.apache.directory.api.ldap.model.message.Message;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.ControlsContainer;
 import org.apache.directory.api.util.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,7 +42,7 @@ import org.slf4j.LoggerFactory;
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class AddControl extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class AddControl extends GrammarAction<ControlsContainer>
 {
     /** The logger */
     private static final Logger LOG = LoggerFactory.getLogger( AddControl.class );
@@ -65,7 +63,7 @@ public class AddControl extends GrammarAction<LdapMessageContainer<MessageDecora
     /**
      * {@inheritDoc}
      */
-    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    public void action( ControlsContainer container ) throws DecoderException
     {
         TLV tlv = container.getCurrentTLV();
 
@@ -73,7 +71,7 @@ public class AddControl extends GrammarAction<LdapMessageContainer<MessageDecora
         // We have to handle the special case of a 0 length OID
         if ( tlv.getLength() == 0 )
         {
-            String msg = I18n.err( I18n.ERR_04097 );
+            String msg = I18n.err( I18n.ERR_04097_NULL_CONTROL_OID );
             LOG.error( msg );
 
             // This will generate a PROTOCOL_ERROR
@@ -86,24 +84,24 @@ public class AddControl extends GrammarAction<LdapMessageContainer<MessageDecora
         // 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 ) ) );
+            String msg = I18n.err( I18n.ERR_04098_INVALID_CONTROL_OID, oidValue );
+            LOG.error( msg );
 
             // This will generate a PROTOCOL_ERROR
-            throw new DecoderException( I18n.err( I18n.ERR_04099, oidValue ) );
+            throw new DecoderException( msg );
         }
 
-        Message message = container.getMessage();
-
-        Control control = container.getLdapCodecService().newControl( oidValue );
-
-        message.addControl( control );
+        CodecControl<?> control = container.getLdapCodecService().newControl( oidValue );
 
+        container.setCurrentControl( control );
+        container.addControl( control );
+        
         // We can have an END transition
         container.setGrammarEndAllowed( true );
 
         if ( IS_DEBUG )
         {
-            LOG.debug( "Control OID : " + oidValue );
+            LOG.debug( "Control OID : {}", oidValue );
         }
     }
 }
diff --git a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/actions/StoreControlCriticality.java
similarity index 78%
copy from ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java
copy to ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/actions/StoreControlCriticality.java
index c221fe0..ad5fe5a 100644
--- a/ldap/codec/core/src/main/java/org/apache/directory/api/ldap/codec/actions/controls/StoreControlCriticality.java
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/actions/StoreControlCriticality.java
@@ -17,7 +17,7 @@
  *  under the License.
  *
  */
-package org.apache.directory.api.ldap.codec.actions.controls;
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.actions;
 
 
 import org.apache.directory.api.asn1.DecoderException;
@@ -27,10 +27,8 @@ import org.apache.directory.api.asn1.ber.tlv.BooleanDecoder;
 import org.apache.directory.api.asn1.ber.tlv.BooleanDecoderException;
 import org.apache.directory.api.asn1.ber.tlv.TLV;
 import org.apache.directory.api.i18n.I18n;
-import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
-import org.apache.directory.api.ldap.codec.api.MessageDecorator;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.ControlsContainer;
 import org.apache.directory.api.ldap.model.message.Control;
-import org.apache.directory.api.ldap.model.message.Message;
 import org.apache.directory.api.util.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -47,7 +45,7 @@ import org.slf4j.LoggerFactory;
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class StoreControlCriticality extends GrammarAction<LdapMessageContainer<MessageDecorator<? extends Message>>>
+public class StoreControlCriticality extends GrammarAction<ControlsContainer>
 {
     /** The logger */
     private static final Logger LOG = LoggerFactory.getLogger( StoreControlCriticality.class );
@@ -68,15 +66,12 @@ public class StoreControlCriticality extends GrammarAction<LdapMessageContainer<
     /**
      * {@inheritDoc}
      */
-    public void action( LdapMessageContainer<MessageDecorator<? extends Message>> container ) throws DecoderException
+    public void action( ControlsContainer container ) throws DecoderException
     {
         TLV tlv = container.getCurrentTLV();
 
         // Get the current control
-        Control control;
-
-        MessageDecorator<? extends Message> message = container.getMessage();
-        control = message.getCurrentControl();
+        Control control = container.getCurrentControl();
 
         // Store the criticality
         // We get the value. If it's a 0, it's a FALSE. If it's
@@ -94,7 +89,7 @@ public class StoreControlCriticality extends GrammarAction<LdapMessageContainer<
         catch ( BooleanDecoderException bde )
         {
             LOG.error( I18n
-                .err( I18n.ERR_04100, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
+                .err( I18n.ERR_04100_BAD_CONTROL_CRITICALITY, Strings.dumpBytes( value.getData() ), bde.getMessage() ) );
 
             // This will generate a PROTOCOL_ERROR
             throw new DecoderException( bde.getMessage(), bde );
@@ -105,7 +100,7 @@ public class StoreControlCriticality extends GrammarAction<LdapMessageContainer<
 
         if ( IS_DEBUG )
         {
-            LOG.debug( "Control criticality : " + control.isCritical() );
+            LOG.debug( "Control criticality : {}", control.isCritical() );
         }
     }
 }
diff --git a/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/actions/StoreControlValue.java b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/actions/StoreControlValue.java
new file mode 100644
index 0000000..bbe35a3
--- /dev/null
+++ b/ldap/extras/codec/src/main/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/controls/actions/StoreControlValue.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.actions;
+
+
+import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
+import org.apache.directory.api.asn1.ber.tlv.BerValue;
+import org.apache.directory.api.asn1.ber.tlv.TLV;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction.controls.ControlsContainer;
+import org.apache.directory.api.util.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The action used to set the value of a control. This is an extension point
+ * where different controls can be plugged in (at least eventually). For now we
+ * hard code controls.
+ * <pre>
+ * Control ::= SEQUENCE {
+ *     ...
+ *     controlValue OCTET STRING OPTIONAL }
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StoreControlValue extends GrammarAction<ControlsContainer>
+{
+    /** The logger */
+    private static final Logger LOG = LoggerFactory.getLogger( StoreControlValue.class );
+
+    /** Speedup for logs */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+
+    /**
+     * Instantiates a new StoreControlValue action.
+     */
+    public StoreControlValue()
+    {
+        super( "Store the control value" );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void action( ControlsContainer container )
+    {
+        TLV tlv = container.getCurrentTLV();
+
+        CodecControl<?> control = container.getCurrentControl();
+
+        // Get the current control
+        BerValue value = tlv.getValue();
+
+        // Store the value - have to handle the special case of a 0 length value
+        if ( tlv.getLength() == 0 )
+        {
+            control.setValue( Strings.EMPTY_BYTES );
+        }
+        else
+        {
+            control.setValue( value.getData() );
+        }
+
+        // We can have an END transition
+        container.setGrammarEndAllowed( true );
+
+        if ( IS_DEBUG )
+        {
+            LOG.debug( "Control value : {}", Strings.dumpBytes( control.getValue() ) );
+        }
+    }
+}
diff --git a/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseTest.java b/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseTest.java
new file mode 100644
index 0000000..57339bc
--- /dev/null
+++ b/ldap/extras/codec/src/test/java/org/apache/directory/api/ldap/extras/extended/ads_impl/endTransaction/EndTransactionResponseTest.java
@@ -0,0 +1,262 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction;
+
+
+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 org.apache.directory.api.asn1.DecoderException;
+import org.apache.directory.api.asn1.EncoderException;
+import org.apache.directory.api.asn1.ber.Asn1Decoder;
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.extras.extended.endTransaction.EndTransactionResponse;
+import org.apache.directory.api.ldap.extras.extended.endTransaction.UpdateControls;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.util.Strings;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+
+/**
+ * Test the EndTransactionResponse codec
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(ConcurrentJunitRunner.class)
+@Concurrency()
+public class EndTransactionResponseTest
+{
+    /**
+     * Test the decoding of a EndTransactionResponse with nothing in it
+     */
+    @Test( expected=DecoderException.class)
+    public void testDecodeEndTransactionResponseEmpty() throws DecoderException
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x02 );
+        bb.put( new byte[]
+            { 0x30, 0x00, // EndTransactionResponse ::= SEQUENCE {
+            } );
+        
+        bb.flip();
+
+        EndTransactionResponseContainer container = new EndTransactionResponseContainer();
+
+        decoder.decode( bb, container );
+    }
+
+
+    /**
+     * Test the decoding of a EndTransactionResponse with a messageId and no updateControls
+     */
+    @Test
+    public void testEndTransactionResponseMessageId() throws DecoderException, EncoderException
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0x05 );
+        bb.put( new byte[]
+            { 0x30, 0x03,              // EndTransactionResponse ::= SEQUENCE {
+                0x02, 0x01, 0x04       // MessageId
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+        EndTransactionResponseContainer container = new EndTransactionResponseContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+        
+        EndTransactionResponse endTransactionResponse = container.getEndTransactionResponse();
+        assertEquals( 4, endTransactionResponse.getFailedMessageId() );
+        assertEquals( 0, endTransactionResponse.getUpdateControls().size() );
+
+        // Check the length
+        assertEquals( 0x05, ( ( EndTransactionResponseDecorator ) endTransactionResponse ).computeLengthInternal() );
+
+        // Check the encoding
+        ByteBuffer bb1 = ( ( EndTransactionResponseDecorator ) endTransactionResponse ).encodeInternal();
+
+        String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+        assertEquals( encodedPdu, decodedPdu );
+    }
+
+
+    /**
+     * Test the decoding of a EndTransactionResponse with updateControls
+     */
+    @Test
+    public void testEndTransactionResponseUpdateControls() throws DecoderException, EncoderException
+    {
+        Asn1Decoder decoder = new Asn1Decoder();
+        ByteBuffer bb = ByteBuffer.allocate( 0xAC );
+        bb.put( new byte[]
+            { 0x30, (byte)0x81, (byte)0xA9,         // EndTransactionResponse ::= SEQUENCE {
+                0x30, (byte)0x81, (byte)0xA6,       // UpdateControls
+                  0x30, 0x5F,                       // updateControl
+                    0x02, 0x01, 0x01,               // messageID
+                    0x30, 0x5A,                     // controls 
+                      0x30, 0x1A,                   // Control ::= SEQUENCE {
+                        0x04, 0x0D,                 // controlType LDAPOID,
+                          '1', '.', '3', '.', '6', '.', '1', '.', '5', '.', '5', '.', '1',
+                        0x01, 0x01, ( byte ) 0xFF,  // criticality BOOLEAN DEFAULT FALSE, 
+                        0x04, 0x06,                 // controlValue OCTET STRING OPTIONAL }
+                          'a', 'b', 'c', 'd', 'e', 'f',
+                      0x30, 0x17,                   // Control ::= SEQUENCE {
+                        0x04, 0x0D,                 // controlType LDAPOID,
+                          '1', '.', '3', '.', '6', '.', '1', '.', '5', '.', '5', '.', '2',
+                        0x04, 0x06,                 // controlValue OCTET STRING OPTIONAL }
+                          'g', 'h', 'i', 'j', 'k', 'l',
+                      0x30, 0x12,                   // Control ::= SEQUENCE {
+                        0x04, 0x0D,                 // controlType LDAPOID,
+                          '1', '.', '3', '.', '6', '.', '1', '.', '5', '.', '5', '.', '3',
+                        0x01, 0x01, ( byte ) 0xFF,  // criticality BOOLEAN DEFAULT FALSE}
+                      0x30, 0x0F,                   // Control ::= SEQUENCE {
+                        0x04, 0x0D,                 // controlType LDAPOID}
+                          '1', '.', '3', '.', '6', '.', '1', '.', '5', '.', '5', '.', '4',
+                  0x30, 0x43,                       // updateControl
+                    0x02, 0x01, 0x02,               // messageID
+                    0x30, 0x3E,                     // controls 
+                      0x30, 0x17,                   // Control ::= SEQUENCE {
+                        0x04, 0x0D,                 // controlType LDAPOID,
+                          '1', '.', '3', '.', '6', '.', '1', '.', '5', '.', '5', '.', '2',
+                        0x04, 0x06,                 // controlValue OCTET STRING OPTIONAL }
+                          'g', 'h', 'i', 'j', 'k', 'l',
+                      0x30, 0x12,                   // Control ::= SEQUENCE {
+                        0x04, 0x0D,                 // controlType LDAPOID,
+                          '1', '.', '3', '.', '6', '.', '1', '.', '5', '.', '5', '.', '3',
+                        0x01, 0x01, ( byte ) 0xFF,  // criticality BOOLEAN DEFAULT FALSE}
+                      0x30, 0x0F,                   // Control ::= SEQUENCE {
+                        0x04, 0x0D,                 // controlType LDAPOID}
+                          '1', '.', '3', '.', '6', '.', '1', '.', '5', '.', '5', '.', '4' 
+
+        } );
+
+        String decodedPdu = Strings.dumpBytes( bb.array() );
+        bb.flip();
+        EndTransactionResponseContainer container = new EndTransactionResponseContainer();
+
+        try
+        {
+            decoder.decode( bb, container );
+        }
+        catch ( DecoderException de )
+        {
+            de.printStackTrace();
+            fail( de.getMessage() );
+        }
+        
+        EndTransactionResponse endTransactionResponse = container.getEndTransactionResponse();
+        assertEquals( -1, endTransactionResponse.getFailedMessageId() );
+        assertEquals( 2, endTransactionResponse.getUpdateControls().size() );
+        
+        UpdateControls updateControls1 = endTransactionResponse.getUpdateControls().get( 0 );
+        assertEquals( 1, updateControls1.getMessageId() );
+        assertNotNull( updateControls1.getControls() );
+        assertEquals( 4, updateControls1.getControls().size() );
+        
+        for ( Control control : updateControls1.getControls() )
+        {
+            switch ( control.getOid() )
+            {
+                case "1.3.6.1.5.5.1" :
+                    assertTrue( control.isCritical() );
+                    assertEquals( "abcdef", Strings.utf8ToString( ( ( CodecControl<?> ) control ).getValue() ) );
+                    break;
+                    
+                case "1.3.6.1.5.5.2" :
+                    assertFalse( control.isCritical() );
+                    assertEquals( "ghijkl", Strings.utf8ToString( ( ( CodecControl<?> ) control ).getValue() ) );
+                    break;
+                    
+                case "1.3.6.1.5.5.3" :
+                    assertTrue( control.isCritical() );
+                    assertNull( ( ( CodecControl<?> ) control ).getValue() );
+                    break;
+                    
+                case "1.3.6.1.5.5.4" :
+                    assertFalse( control.isCritical() );
+                    assertNull( ( ( CodecControl<?> ) control ).getValue() );
+                    break;
+                    
+                default :
+                    fail();
+                    break;
+            }
+        }
+
+        UpdateControls updateControls2 = endTransactionResponse.getUpdateControls().get( 1 );
+        assertEquals( 2, updateControls2.getMessageId() );
+        assertNotNull( updateControls2.getControls() );
+        assertEquals( 3, updateControls2.getControls().size() );
+        
+        for ( Control control : updateControls2.getControls() )
+        {
+            switch ( control.getOid() )
+            {
+                case "1.3.6.1.5.5.2" :
+                    assertFalse( control.isCritical() );
+                    assertEquals( "ghijkl", Strings.utf8ToString( ( ( CodecControl<?> ) control ).getValue() ) );
+                    break;
+                    
+                case "1.3.6.1.5.5.3" :
+                    assertTrue( control.isCritical() );
+                    assertNull( ( ( CodecControl<?> ) control ).getValue() );
+                    break;
+                    
+                case "1.3.6.1.5.5.4" :
+                    assertFalse( control.isCritical() );
+                    assertNull( ( ( CodecControl<?> ) control ).getValue() );
+                    break;
+                    
+                default :
+                    fail();
+                    break;
+            }
+        }
+
+        // Check the length
+        assertEquals( 0xAC, ( ( EndTransactionResponseDecorator ) endTransactionResponse ).computeLengthInternal() );
+
+        // Check the encoding
+        ByteBuffer bb1 = ( ( EndTransactionResponseDecorator ) endTransactionResponse ).encodeInternal();
+
+        String encodedPdu = Strings.dumpBytes( bb1.array() );
+
+        assertEquals( encodedPdu, decodedPdu );
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
elecharny@apache.org.

Mime
View raw message