You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2005/06/07 00:29:29 UTC

svn commit: r185068 - /directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/ldap/codec/grammars/FilterGrammar.java

Author: elecharny
Date: Mon Jun  6 15:29:28 2005
New Revision: 185068

URL: http://svn.apache.org/viewcvs?rev=185068&view=rev
Log:
Added the first SearchRequest sub-grammar, and the most important part of it : FilterGrammar. 
Not finished yet, some transitions need to be added.

Added:
    directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/ldap/codec/grammars/FilterGrammar.java

Added: directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/ldap/codec/grammars/FilterGrammar.java
URL: http://svn.apache.org/viewcvs/directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/ldap/codec/grammars/FilterGrammar.java?rev=185068&view=auto
==============================================================================
--- directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/ldap/codec/grammars/FilterGrammar.java (added)
+++ directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/ldap/codec/grammars/FilterGrammar.java Mon Jun  6 15:29:28 2005
@@ -0,0 +1,665 @@
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.asn1.ldap.codec.grammars;
+
+import org.apache.asn1.AbstractPOJO;
+import org.apache.asn1.DecoderException;
+import org.apache.asn1.ber.containers.IAsn1Container;
+import org.apache.asn1.ber.grammar.AbstractGrammar;
+import org.apache.asn1.ber.grammar.GrammarAction;
+import org.apache.asn1.ber.grammar.GrammarTransition;
+import org.apache.asn1.ber.grammar.IGrammar;
+import org.apache.asn1.ber.tlv.TLV;
+import org.apache.asn1.ldap.codec.LdapMessageContainer;
+import org.apache.asn1.ldap.codec.primitives.LdapString;
+import org.apache.asn1.ldap.pojo.AttributeValueAssertionPOJO;
+import org.apache.asn1.ldap.pojo.LdapMessagePOJO;
+import org.apache.asn1.ldap.pojo.SearchRequestPOJO;
+import org.apache.asn1.ldap.pojo.filters.AndFilterPOJO;
+import org.apache.asn1.ldap.pojo.filters.AttributeValueAssertionFilterPOJO;
+import org.apache.asn1.ldap.pojo.filters.FilterPOJO;
+import org.apache.asn1.ldap.pojo.filters.NotFilterPOJO;
+import org.apache.asn1.ldap.pojo.filters.OrFilterPOJO;
+import org.apache.asn1.primitives.OctetString;
+import org.apache.asn1.util.MutableString;
+
+import org.apache.log4j.Logger;
+
+
+/**
+ * This class implements the Filter grammar. All the actions are declared in this
+ * class. As it is a singleton, these declaration are only done once.
+ * 
+ * If an action is to be added or modified, this is where the work is to be done !
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class FilterGrammar extends AbstractGrammar implements IGrammar
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** The logger */
+    private static final Logger log = Logger.getLogger( FilterGrammar.class );
+
+    /** Logging speed up  */
+    private static final boolean DEBUG = log.isDebugEnabled();
+
+    /** The instance of grammar. FilterGrammar is a singleton */
+    private static IGrammar instance = new FilterGrammar();
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    /**
+     * Creates a new LdapResultGrammar object.
+     */
+    private FilterGrammar()
+    {
+        name              = FilterGrammar.class.getName();
+        statesEnum        = LdapStatesEnum.getInstance();
+
+        super.transitions = new GrammarTransition[LdapStatesEnum.LAST_FILTER_STATE][256];
+
+        //============================================================================================
+        // Search Request And Filter
+        // This is quite complicated, because we have a tree structure to build,
+        // and we may have many elements on each node. For instance, considering the 
+        // search filter :
+        // (& (| (a = b) (c = d)) (! (e = f)) (attr =* h))
+        // We will have to create an And filter with three children :
+        //  - an Or child,
+        //  - a Not child
+        //  - and a Present child.
+        // The Or child will also have two children.
+        //
+        // We know when we have a children while decoding the PDU, because the length
+        // of its father has not yet reached its expected length.
+        //
+        // This search filter :
+        // (&(|(objectclass=top)(ou=contacts))(!(objectclass=ttt))(objectclass=*top))
+        // is encoded like this :
+        //                              +----------------+---------------+
+        //                              | ExpectedLength | CurrentLength |
+        //+-----------------------------+----------------+---------------+
+        //|A0 52                        | 82             | 0             | new level 1
+        //|   A1 24                     | 82 36          | 0 0           | new level 2
+        //|      A3 12                  | 82 36 18       | 0 0 0         | new level 3
+        //|         04 0B 'objectclass' | 82 36 18       | 0 0 13        |
+        //|         04 03 'top'         | 82 36 18       | 0 20 18       | 
+        //|                             |       ^               ^        |
+        //|                             |       |               |        |
+        //|                             |       +---------------+        |
+        //+-----------------------------* end level 3 -------------------*
+        //|      A3 0E                  | 82 36 14       | 0 0 0         | new level 3
+        //|         04 02 'ou'          | 82 36 14       | 0 0 4         |
+        //|         04 08 'contacts'    | 82 36 14       | 38 36 14      | 
+        //|                             |    ^  ^             ^  ^       |
+        //|                             |    |  |             |  |       |
+        //|                             |    |  +-------------|--+       |
+        //|                             |    +----------------+          |
+        //+-----------------------------* end level 3, end level 2 ------*
+        //|   A2 14                     | 82 20          | 38 0          | new level 2
+        //|      A3 12                  | 82 20 18       | 38 0 0        | new level 3
+        //|         04 0B 'objectclass' | 82 20 18       | 38 0 13       | 
+        //|         04 03 'ttt'         | 82 20 18       | 60 20 18      |
+        //|                             |    ^  ^             ^  ^       |
+        //|                             |    |  |             |  |       |
+        //|                             |    |  +-------------|--+       |
+        //|                             |    +----------------+          |
+        //+-----------------------------* end level 3, end level 2 ------*
+        //|   A4 14                     | 82 20          | 60 0          | new level 2
+        //|      04 0B 'objectclass'    | 82 20          | 60 13         |
+        //|      30 05                  | 82 20          | 60 13         |
+        //|         82 03 'top'         | 82 20          | 82 20         | 
+        //|                             | ^  ^             ^  ^          |
+        //|                             | |  |             |  |          |
+        //|                             | |  +-------------|--+          |
+        //|                             | +----------------+             |
+        //+-----------------------------* end level 2, end level 1 ------*
+        //+-----------------------------+----------------+---------------+
+        //
+        // When the current length equals the expected length of the father PDU,
+        // then we are able to 'close' the father : it has all its children. This
+        // is propagated through all the tree, until either there are no more
+        // parents, or the expected length of the father is different from the
+        // current length.
+        //                              
+        //============================================================================================
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter, (Tag)
+        //     ...
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0xA0] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_AND_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     ...
+        //     or              [1] SET OF Filter, (Tag)
+        //     ...
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0xA1] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_OR_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     ...
+        //     not             [2] Filter, (Tag)
+        //     ...
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0xA2] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_NOT_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     ...
+        //     equalityMatch   [3] AttributeValueAssertion, (Tag)
+        //     ...
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0xA3] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_EQUALITY_MATCH_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     ...
+        //     substrings      [4] SubstringFilter, (Tag)
+        //     ...
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0xA4] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_SUBSTRINGS_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     ...
+        //     greaterOrEqual  [5] AttributeValueAssertion, (Tag)
+        //     ...
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0xA5] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_GREATER_OR_EQUAL_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     ...
+        //     lessOrEqual     [6] AttributeValueAssertion, (Tag)
+        //     ...
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0xA6] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_LESS_OR_EQUAL_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     ...
+        //     present         [7] AttributeDescription, (Tag)
+        //     ...
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0x87] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_PRESENT_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     ...
+        //     approxMatch     [8] AttributeValueAssertion, (Tag)
+        //     ...
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0xA8] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_APPROX_MATCH_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     ...
+        //     extensibleMatch [9] MatchingRuleAssertion } (Tag)
+        // Nothing to do
+        super.transitions[LdapStatesEnum.FILTER_TAG][0xA9] = new GrammarTransition(
+                LdapStatesEnum.FILTER_TAG, LdapStatesEnum.FILTER_EXTENSIBLE_MATCH_LENGTH, null );
+
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter, (Length)
+        //     ...
+        // We have to control the length to know if we have a completed level or not.
+        super.transitions[LdapStatesEnum.FILTER_AND_LENGTH][0xA0] = new GrammarTransition(
+                LdapStatesEnum.FILTER_AND_LENGTH, LdapStatesEnum.FILTER_AND_VALUE,
+                new GrammarAction( "Init And Filter" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessagePOJO      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+                        SearchRequestPOJO searchRequest = ldapMessage.getSearchRequest();
+
+                        TLV tlv            = ldapMessageContainer.getCurrentTLV();
+
+                        // We can allocate the SearchRequestPOJO
+                        FilterPOJO andFilter = new AndFilterPOJO();
+                        
+                        // Get the parent, if any
+                        FilterPOJO currentFilter = searchRequest.getCurrentFilter();
+                        
+                        if (currentFilter != null)
+                        {
+                            // Ok, we have a parent. The new Filter will be added to
+                            // this parent, then. We also have to check the length
+                            // against the parent.
+                            checkLength( currentFilter, tlv );
+                            currentFilter.addFilter(andFilter);
+                            andFilter.setFather( currentFilter );
+                        }
+                        else
+                        {
+                            // No parent. This Filter will become the root.
+                            // First, check the length to see if it does not exceed its father
+                            // expected length. (If there is no parent, we have to check the
+                            // length against the SearchRequestPOJO )
+                            checkLength( searchRequest, tlv );
+
+                            searchRequest.setCurrentFilter(andFilter);
+                            searchRequest.setFilter(andFilter);
+                            andFilter.setFather( searchRequest );
+                        }
+
+                        // As this is a new Constructed object, we have to init its length
+                        int expectedLength = tlv.getLength().getLength();
+
+                        andFilter.setExpectedLength( expectedLength );
+                        andFilter.setCurrentLength( 0 );
+                    }
+                } );
+
+        // Filter ::= CHOICE {
+        //     and             [0] SET OF Filter, (Value)
+        //     ...
+        // We just have to switch to the initial state of Filter, because this is what
+        // we will get !
+        super.transitions[LdapStatesEnum.FILTER_AND_VALUE][0xA0] = new GrammarTransition(
+                LdapStatesEnum.FILTER_AND_VALUE, LdapStatesEnum.FILTER_TAG, null);
+
+        // Filter ::= CHOICE {
+        //     or              [1] SET OF Filter, (Length)
+        //     ...
+        // We have to control the length to know if we have a completed level or not.
+        super.transitions[LdapStatesEnum.FILTER_OR_LENGTH][0xA1] = new GrammarTransition(
+                LdapStatesEnum.FILTER_OR_LENGTH, LdapStatesEnum.FILTER_OR_VALUE,
+                new GrammarAction( "Init Or Filter" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessagePOJO      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+                        SearchRequestPOJO searchRequest = ldapMessage.getSearchRequest();
+
+                        TLV tlv            = ldapMessageContainer.getCurrentTLV();
+
+                        // We can allocate the SearchRequestPOJO
+                        FilterPOJO orFilter = new OrFilterPOJO();
+                        
+                        // Get the parent, if any
+                        FilterPOJO currentFilter = searchRequest.getCurrentFilter();
+                        
+                        if (currentFilter != null)
+                        {
+                            // Ok, we have a parent. The new Filter will be added to
+                            // this parent, then. We also have to check the length
+                            // against the parent.
+                            checkLength( currentFilter, tlv );
+                            currentFilter.addFilter(orFilter);
+                            orFilter.setFather( currentFilter );
+                        }
+                        else
+                        {
+                            // No parent. This Filter will become the root.
+                            // First, check the length to see if it does not exceed its father
+                            // expected length. (If there is no parent, we have to check the
+                            // length against the SearchRequestPOJO )
+                            checkLength( searchRequest, tlv );
+                            searchRequest.setFilter(orFilter);
+                            orFilter.setFather( searchRequest );
+                        }
+
+                        searchRequest.setCurrentFilter(orFilter);
+                        
+                        // As this is a new Constructed object, we have to init its length
+                        int expectedLength = tlv.getLength().getLength();
+
+                        orFilter.setExpectedLength( expectedLength );
+                        orFilter.setCurrentLength( 0 );
+                    }
+                } );
+
+        // Filter ::= CHOICE {
+        //     or              [1] SET OF Filter, (Value)
+        //     ...
+        // We just have to switch to the initial state of Filter, because this is what
+        // we will get !
+        super.transitions[LdapStatesEnum.FILTER_OR_VALUE][0xA1] = new GrammarTransition(
+                LdapStatesEnum.FILTER_OR_VALUE, LdapStatesEnum.FILTER_TAG, null);
+
+        // Filter ::= CHOICE {
+        //     not             [2] Filter, (Length)
+        //     ...
+        // We have to control the length to know if we have a completed level or not.
+        super.transitions[LdapStatesEnum.FILTER_NOT_LENGTH][0xA2] = new GrammarTransition(
+                LdapStatesEnum.FILTER_NOT_LENGTH, LdapStatesEnum.FILTER_TAG,
+                new GrammarAction( "Init Not Filter" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessagePOJO      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+                        SearchRequestPOJO searchRequest = ldapMessage.getSearchRequest();
+
+                        TLV tlv            = ldapMessageContainer.getCurrentTLV();
+
+                        // We can allocate the SearchRequestPOJO
+                        FilterPOJO notFilter = new NotFilterPOJO();
+                        
+                        // Get the parent, if any
+                        FilterPOJO currentFilter = searchRequest.getCurrentFilter();
+                        
+                        if (currentFilter != null)
+                        {
+                            // Ok, we have a parent. The new Filter will be added to
+                            // this parent, then. We also have to check the length
+                            // against the parent.
+                            checkLength( currentFilter, tlv );
+                            currentFilter.addFilter(notFilter);
+                            notFilter.setFather( currentFilter );
+                        }
+                        else
+                        {
+                            // No parent. This Filter will become the root.
+                            // First, check the length to see if it does not exceed its father
+                            // expected length. (If there is no parent, we have to check the
+                            // length against the SearchRequestPOJO )
+                            checkLength( searchRequest, tlv );
+
+                            searchRequest.setCurrentFilter(notFilter);
+                            searchRequest.setFilter(notFilter);
+                            notFilter.setFather( searchRequest );
+                        }
+
+                        searchRequest.setCurrentFilter(notFilter);
+                        
+                        // As this is a new Constructed object, we have to init its length
+                        int expectedLength = tlv.getLength().getLength();
+
+                        notFilter.setExpectedLength( expectedLength );
+                        notFilter.setCurrentLength( 0 );
+                    }
+                } );
+
+        // Filter ::= CHOICE {
+        //     not             [2] Filter, (Value)
+        //     ...
+        // We just have to switch to the initial state of Filter, because this is what
+        // we will get !
+        super.transitions[LdapStatesEnum.FILTER_NOT_VALUE][0xA2] = new GrammarTransition(
+                LdapStatesEnum.FILTER_NOT_VALUE, LdapStatesEnum.FILTER_TAG, null);
+
+        // Filter ::= CHOICE {
+        //     equalityMatch   [3] AttributeValueAssertion, (Length)
+        //     ...
+        // We have to control the length to know if we have a completed level or not.
+        super.transitions[LdapStatesEnum.FILTER_EQUALITY_MATCH_LENGTH][0xA3] = new GrammarTransition(
+                LdapStatesEnum.FILTER_EQUALITY_MATCH_LENGTH, LdapStatesEnum.FILTER_EQUALITY_MATCH_VALUE,
+                new GrammarAction( "Init Equality Match Filter" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessagePOJO      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+                        SearchRequestPOJO searchRequest = ldapMessage.getSearchRequest();
+
+                        TLV tlv            = ldapMessageContainer.getCurrentTLV();
+
+                        // We can allocate the SearchRequestPOJO
+                        FilterPOJO equalityMatchFilter = new AttributeValueAssertionFilterPOJO();
+                        
+                        // Get the parent, if any
+                        FilterPOJO currentFilter = searchRequest.getCurrentFilter();
+                        
+                        if (currentFilter != null)
+                        {
+                            // Ok, we have a parent. The new Filter will be added to
+                            // this parent, then. We also have to check the length
+                            // against the parent.
+                            checkLength( currentFilter, tlv );
+                            currentFilter.addFilter(equalityMatchFilter);
+                            equalityMatchFilter.setFather( currentFilter );
+                        }
+                        else
+                        {
+                            // No parent. This Filter will become the root.
+                            // First, check the length to see if it does not exceed its father
+                            // expected length. (If there is no parent, we have to check the
+                            // length against the SearchRequestPOJO )
+                            checkLength( searchRequest, tlv );
+
+                            searchRequest.setCurrentFilter(equalityMatchFilter);
+                            equalityMatchFilter.setFather( searchRequest );
+                            searchRequest.setFilter(equalityMatchFilter);
+                        }
+
+                        searchRequest.setCurrentFilter(equalityMatchFilter);
+
+                        // As this is a new Constructed object, we have to init its length
+                        int expectedLength = tlv.getLength().getLength();
+
+                        equalityMatchFilter.setExpectedLength( expectedLength );
+                        equalityMatchFilter.setCurrentLength( 0 );
+                    }
+                } );
+
+        // Filter ::= CHOICE {
+        //     equalityMatch   [3] AttributeValueAssertion, (Value)
+        //     ...
+        // We will create the filter container (as this is an equalityMatch filter,
+        // we will create an AttributeValueAssertionFilterPOJO).
+        super.transitions[LdapStatesEnum.FILTER_EQUALITY_MATCH_VALUE][0xA3] = new GrammarTransition(
+                LdapStatesEnum.FILTER_EQUALITY_MATCH_VALUE, LdapStatesEnum.FILTER_ATTRIBUTE_DESC_TAG, null); 
+                
+        // AttributeValueAssertion ::= SEQUENCE {
+        //    attributeDesc   AttributeDescription, (TAG)
+        //     ...
+        // Nothing to do.
+        super.transitions[LdapStatesEnum.FILTER_ATTRIBUTE_DESC_TAG][0x04] = new GrammarTransition(
+                LdapStatesEnum.FILTER_ATTRIBUTE_DESC_TAG, LdapStatesEnum.FILTER_ATTRIBUTE_DESC_LENGTH, null);
+
+        // AttributeValueAssertion ::= SEQUENCE {
+        //    attributeDesc   AttributeDescription, (LENGTH)
+        //     ...
+        // We have to check the length
+        super.transitions[LdapStatesEnum.FILTER_ATTRIBUTE_DESC_LENGTH][0x04] = new GrammarTransition(
+                LdapStatesEnum.FILTER_ATTRIBUTE_DESC_LENGTH, LdapStatesEnum.FILTER_ATTRIBUTE_DESC_VALUE, 
+                new GrammarAction( "Check AttributeDesc length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        // We will check the length against the current filter
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessagePOJO      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+                        SearchRequestPOJO searchRequest = ldapMessage.getSearchRequest();
+
+                        FilterPOJO     currentFilter =
+                            searchRequest.getCurrentFilter();
+                        
+                        TLV                  tlv = ldapMessageContainer.getCurrentTLV();
+
+                        checkLength( currentFilter, tlv );
+                        return;
+                    }
+                });
+
+        // AttributeValueAssertion ::= SEQUENCE {
+        //    attributeDesc   AttributeDescription, (VALUE)
+        //     ...
+        // We have to set the attribute description in the current filter.
+        // It could be an equalityMatch, greaterOrEqual, lessOrEqual or an
+        // approxMatch filter.
+        super.transitions[LdapStatesEnum.FILTER_ATTRIBUTE_DESC_VALUE][0x04] = new GrammarTransition(
+                LdapStatesEnum.FILTER_ATTRIBUTE_DESC_VALUE, LdapStatesEnum.FILTER_ASSERTION_VALUE_TAG, 
+                new GrammarAction( "Init attributeDesc Value" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessagePOJO      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+                        SearchRequestPOJO searchRequest = ldapMessage.getSearchRequest();
+
+                        TLV tlv            = ldapMessageContainer.getCurrentTLV();
+                        MutableString attributeDesc = LdapString.parse(tlv.getValue().getData());
+                        
+                        AttributeValueAssertionPOJO assertion = new AttributeValueAssertionPOJO();
+                        assertion.setAttributeDesc(attributeDesc);
+                        
+                        AttributeValueAssertionFilterPOJO currentFilter = (AttributeValueAssertionFilterPOJO)searchRequest.getCurrentFilter();
+                        currentFilter.setAssertion(assertion);
+                    }
+                });
+
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     ...
+        //    assertionValue  AssertionValue } (TAG)
+        // Nothing to do.
+        super.transitions[LdapStatesEnum.FILTER_ASSERTION_VALUE_TAG][0x04] = new GrammarTransition(
+                LdapStatesEnum.FILTER_ASSERTION_VALUE_TAG, LdapStatesEnum.FILTER_ASSERTION_VALUE_LENGTH, null);
+
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     ...
+        //    assertionValue  AssertionValue } (LENGTH)
+        // We have to check the length
+        super.transitions[LdapStatesEnum.FILTER_ASSERTION_VALUE_LENGTH][0x04] = new GrammarTransition(
+                LdapStatesEnum.FILTER_ASSERTION_VALUE_LENGTH, LdapStatesEnum.FILTER_ASSERTION_VALUE_VALUE, 
+                new GrammarAction( "Check AssertionValue length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        // We will check the length against the current filter
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessagePOJO      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+                        SearchRequestPOJO searchRequest = ldapMessage.getSearchRequest();
+
+                        FilterPOJO     currentFilter =
+                            searchRequest.getCurrentFilter();
+                        
+                        TLV                  tlv = ldapMessageContainer.getCurrentTLV();
+
+                        checkLength( currentFilter, tlv );
+                        return;
+                    }
+                });
+
+        // AttributeValueAssertion ::= SEQUENCE {
+        //     ...
+        //    assertionValue  AssertionValue } (VALUE)
+        // We have to set the attribute description in the current filter.
+        // It could be an equalityMatch, greaterOrEqual, lessOrEqual or an
+        // approxMatch filter.
+        // Whgen finished, we will transit to the first state.
+        super.transitions[LdapStatesEnum.FILTER_ASSERTION_VALUE_VALUE][0x04] = new GrammarTransition(
+                LdapStatesEnum.FILTER_ASSERTION_VALUE_VALUE, LdapStatesEnum.FILTER_TAG, 
+                new GrammarAction( "Init AssertionValue Value" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessagePOJO      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+                        SearchRequestPOJO searchRequest = ldapMessage.getSearchRequest();
+
+                        TLV tlv            = ldapMessageContainer.getCurrentTLV();
+                        OctetString assertionValue = new OctetString();
+                        assertionValue.setData(tlv.getValue().getData());
+                        
+                        AttributeValueAssertionFilterPOJO currentFilter = (AttributeValueAssertionFilterPOJO)searchRequest.getCurrentFilter();
+                        AttributeValueAssertionPOJO assertion = currentFilter.getAssertion();
+                        assertion.setAssertionValue(assertionValue);
+                        
+                        // We now have to get back to the nearest filter which is not terminal.
+                        unstackCurrent(searchRequest);
+                    }
+                });
+
+    }
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * This class is a singleton.
+     *
+     * @return An instance on this grammar
+     */
+    public static IGrammar getInstance()
+    {
+        return instance;
+    }
+    
+    /**
+     * This method is used to clear the filter's stack for terminated elements. An element
+     * is considered as terminated either if :
+     *  - it's a final element (ie an element which cannot contains a Filter)
+     *  - its current length equals its expected length.
+     * 
+     * @param searchRequest The request being decoded
+     */
+    private void unstackCurrent(SearchRequestPOJO searchRequest)
+    {
+        FilterPOJO currentFilter = searchRequest.getCurrentFilter();
+        
+        while (currentFilter != null)
+        {
+            if ( ( currentFilter instanceof AndFilterPOJO ) | ( currentFilter instanceof OrFilterPOJO ) | ( currentFilter instanceof NotFilterPOJO ) )
+            {
+                if ( currentFilter.getExpectedLength() == currentFilter.getCurrentLength())
+                {
+                    // The current element is not terminal, but it has been fully decoded
+                    // so we will pop it from the stack
+                    AbstractPOJO element = currentFilter.getFather();
+                    
+                    // We have to check that the father is a FilterPOJO.
+                    if (element instanceof FilterPOJO)
+                    {
+                        currentFilter = (FilterPOJO)element;
+                    }
+                    else
+                    {
+                        // The element is a SearchRequestPOJO, so the stack is
+                        // empty. It's over !
+                        currentFilter = null;
+                        return;
+                    }
+                }
+                else
+                {
+                    // Ok, we have a non terminal element which is not fully decoded.
+                    searchRequest.setCurrentFilter(currentFilter);
+                    return;
+                }
+            } 
+            else
+            {
+                // The current element is a terminal element
+                currentFilter = (FilterPOJO)currentFilter.getFather();
+            }
+        }
+        
+        return;
+    }
+}