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 2006/12/20 17:14:56 UTC

svn commit: r489128 - in /directory/trunks/shared/ldap/src: main/antlr/ main/java/org/apache/directory/shared/ldap/aci/ test/java/org/apache/directory/shared/ldap/aci/

Author: elecharny
Date: Wed Dec 20 08:14:55 2006
New Revision: 489128

URL: http://svn.apache.org/viewvc?view=rev&rev=489128
Log:
Added a syntax checker for ACI Item
Added the related tests
the tests don't check that an element is not duplicated nor that it is missing

Added:
    directory/trunks/shared/ldap/src/main/antlr/ACIItemChecker.g
    directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemChecker.java
    directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemChecker.java
    directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemCheckerLexer.java
    directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ACIItemChekerTest.java

Added: directory/trunks/shared/ldap/src/main/antlr/ACIItemChecker.g
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/antlr/ACIItemChecker.g?view=auto&rev=489128
==============================================================================
--- directory/trunks/shared/ldap/src/main/antlr/ACIItemChecker.g (added)
+++ directory/trunks/shared/ldap/src/main/antlr/ACIItemChecker.g Wed Dec 20 08:14:55 2006
@@ -0,0 +1,822 @@
+header
+{
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+
+package org.apache.directory.shared.ldap.aci;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Enumeration;
+
+import javax.naming.directory.Attribute;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.NamingException;
+
+import org.apache.directory.shared.ldap.filter.AssertionEnum;
+import org.apache.directory.shared.ldap.filter.BranchNode;
+import org.apache.directory.shared.ldap.filter.ExprNode;
+import org.apache.directory.shared.ldap.filter.FilterParserImpl;
+import org.apache.directory.shared.ldap.filter.LeafNode;
+import org.apache.directory.shared.ldap.filter.SimpleNode;
+import org.apache.directory.shared.ldap.name.NameComponentNormalizer;
+import org.apache.directory.shared.ldap.subtree.SubtreeSpecification;
+import org.apache.directory.shared.ldap.subtree.SubtreeSpecificationModifier;
+import org.apache.directory.shared.ldap.util.ComponentsMonitor;
+import org.apache.directory.shared.ldap.util.MandatoryAndOptionalComponentsMonitor;
+import org.apache.directory.shared.ldap.util.MandatoryComponentsMonitor;
+import org.apache.directory.shared.ldap.util.NamespaceTools;
+import org.apache.directory.shared.ldap.util.NoDuplicateKeysMap;
+import org.apache.directory.shared.ldap.util.OptionalComponentsMonitor;
+import org.apache.directory.shared.ldap.name.LdapDN;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+}
+
+
+// ----------------------------------------------------------------------------
+// parser class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * The antlr generated ACIItem checker.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class AntlrACIItemChecker extends Parser;
+
+
+// ----------------------------------------------------------------------------
+// parser options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 1; // ;-)
+    defaultErrorHandler = false;
+}
+
+
+// ----------------------------------------------------------------------------
+// imaginary tokens
+// ----------------------------------------------------------------------------
+
+tokens
+{
+    ATTRIBUTE_VALUE_CANDIDATE;
+    RANGE_OF_VALUES_CANDIDATE;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser initialization
+// ----------------------------------------------------------------------------
+
+{
+    // subordinate parser instances
+    private final FilterParserImpl filterParser = new FilterParserImpl();
+    
+    private boolean isNormalizing = false;
+    NameComponentNormalizer normalizer;
+    
+    /**
+     * Creates a (normalizing) subordinate DnParser for parsing Names.
+     * This method MUST be called for each instance while we cannot do
+     * constructor overloading for this class.
+     *
+     * @return the DnParser to be used for parsing Names
+     */
+    public void init()
+    {
+    }
+
+    /**
+     * Sets the NameComponentNormalizer for this parser's dnParser.
+     */
+    public void setNormalizer(NameComponentNormalizer normalizer)
+    {
+        this.normalizer = normalizer;
+        this.isNormalizing = true;
+    }
+
+    private int token2Integer( Token token ) throws RecognitionException
+    {
+        int i = 0;
+        
+        try
+        {
+            i = Integer.parseInt( token.getText());
+        }
+        catch ( NumberFormatException e )
+        {
+            throw new RecognitionException( "Value of INTEGER token " +
+                                            token.getText() +
+                                            " cannot be converted to an Integer" );
+        }
+        
+        return i;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+// parser productions
+// ----------------------------------------------------------------------------
+
+wrapperEntryPoint
+    :
+    ( SP )* theACIItem ( SP )* EOF
+    ;
+
+theACIItem
+    :
+    OPEN_CURLY
+        ( SP )* mainACIItemComponent ( SP )*
+            ( SEP ( SP )* mainACIItemComponent ( SP )* )*
+    CLOSE_CURLY
+    ;
+    
+mainACIItemComponent
+    :
+    aci_identificationTag
+    | aci_precedence
+    | aci_authenticationLevel
+    | aci_itemOrUserFirst
+    ;
+    
+aci_identificationTag
+    :
+    ID_identificationTag ( SP )+ SAFEUTF8STRING
+    ;
+
+aci_precedence
+    :
+    precedence
+    ;
+
+precedence
+    :
+    ID_precedence ( SP )+ INTEGER
+    ;
+
+aci_authenticationLevel
+    :
+    ID_authenticationLevel ( SP )+ authenticationLevel
+    ;
+
+authenticationLevel
+    :
+    ID_none
+    |
+    ID_simple
+    |
+    ID_strong
+    ;
+
+aci_itemOrUserFirst
+    :
+    ID_itemOrUserFirst ( SP )+ itemOrUserFirst
+    ;
+
+itemOrUserFirst
+    :
+    itemFirst | userFirst
+    ;
+
+itemFirst
+    :
+    ID_itemFirst ( SP )* COLON ( SP )*
+        OPEN_CURLY ( SP )*
+            ( 
+              protectedItems ( SP )*
+                SEP ( SP )* itemPermissions
+            | // relaxing
+              itemPermissions ( SP )*
+                SEP ( SP )* protectedItems
+            )
+        ( SP )* CLOSE_CURLY
+    ;
+
+userFirst
+    :
+    ID_userFirst ( SP )* COLON ( SP )*
+        OPEN_CURLY ( SP )*
+            (
+              userClasses ( SP )*
+                SEP ( SP )* userPermissions
+            | // relaxing
+              userPermissions ( SP )*
+                SEP ( SP )* userClasses
+            )
+        ( SP )* CLOSE_CURLY
+    ;
+
+protectedItems
+    :
+    ID_protectedItems ( SP )*
+        OPEN_CURLY ( SP )*
+            (
+                protectedItem ( SP )*
+                    ( SEP ( SP )* protectedItem ( SP )* )*
+            )?
+        CLOSE_CURLY
+    ;
+
+protectedItem
+    :
+    entry
+    | allUserAttributeTypes
+    | attributeType
+    | allAttributeValues 
+    | allUserAttributeTypesAndValues
+    | attributeValue
+    | selfValue
+    | rangeOfValues
+    | maxValueCount
+    | maxImmSub
+    | restrictedBy
+    | classes
+    ;
+
+entry
+    :
+    ID_entry
+    ;
+
+allUserAttributeTypes
+    :
+    ID_allUserAttributeTypes
+    ;
+
+attributeType
+    :
+    ID_attributeType ( SP )+ attributeTypeSet
+    ;
+
+allAttributeValues
+    :
+    ID_allAttributeValues ( SP )+ attributeTypeSet
+    ;
+
+allUserAttributeTypesAndValues
+    :
+    ID_allUserAttributeTypesAndValues
+    ;
+
+attributeValue
+    :
+    ATTRIBUTE_VALUE_CANDIDATE // ate the identifier for subordinate dn parser workaround
+    ;
+
+selfValue
+    :
+    ID_selfValue ( SP )+ attributeTypeSet
+    ;
+
+rangeOfValues
+    :
+    RANGE_OF_VALUES_CANDIDATE
+    ;
+
+maxValueCount
+    :
+    ID_maxValueCount ( SP )+
+    OPEN_CURLY ( SP )*
+        aMaxValueCount ( SP )*
+            ( SEP ( SP )* aMaxValueCount ( SP )*
+            )*
+    CLOSE_CURLY
+    ;
+
+aMaxValueCount
+    :
+    OPEN_CURLY ( SP )*
+        (
+          ID_type ( SP )+ oid ( SP )* SEP ( SP )*
+          ID_maxCount ( SP )+ INTEGER
+        | // relaxing
+          ID_maxCount ( SP )+ INTEGER ( SP )* SEP ( SP )*
+          ID_type ( SP )+ oid
+        )
+    ( SP )* CLOSE_CURLY
+    ;
+
+maxImmSub
+    :
+    ID_maxImmSub ( SP )+ INTEGER
+    ;
+
+restrictedBy
+    :
+    ID_restrictedBy ( SP )+
+        OPEN_CURLY ( SP )*
+            restrictedValue ( SP )*
+                    ( SEP ( SP )* restrictedValue ( SP )*
+                    )*
+        CLOSE_CURLY
+    ;
+
+restrictedValue
+    :
+    OPEN_CURLY ( SP )*
+        (
+          ID_type ( SP )+ oid ( SP )* SEP ( SP )*
+          ID_valuesIn ( SP )+ oid
+        | // relaxing
+          ID_valuesIn ( SP )+ oid ( SP )* SEP ( SP )*
+          ID_type ( SP )+ oid
+        )
+    ( SP )* CLOSE_CURLY
+    ;
+
+attributeTypeSet 
+    :
+    OPEN_CURLY ( SP )*
+        oid ( SP )*
+            ( SEP ( SP )* oid ( SP )*
+            )*
+    CLOSE_CURLY
+    ;
+
+classes
+    :
+    ID_classes ( SP )+ refinement
+    ;
+
+itemPermissions
+    :
+    ID_itemPermissions ( SP )+
+        OPEN_CURLY ( SP )*
+            ( itemPermission ( SP )*
+                ( SEP ( SP )* itemPermission ( SP )*
+                )*
+            )?
+        CLOSE_CURLY
+    ;
+
+itemPermission
+    :
+    OPEN_CURLY ( SP )*
+        anyItemPermission ( SP )*
+            ( SEP ( SP )* anyItemPermission ( SP )* )*
+    CLOSE_CURLY
+    ;
+
+anyItemPermission
+    :
+    precedence
+    | userClasses
+    | grantsAndDenials
+    ;
+
+grantsAndDenials
+    :
+    ID_grantsAndDenials ( SP )+
+    OPEN_CURLY ( SP )*
+        ( grantAndDenial ( SP )*
+            ( SEP ( SP )* grantAndDenial ( SP )*
+            )*
+        )?
+    CLOSE_CURLY
+    ;
+
+grantAndDenial
+    :
+    ID_grantAdd 
+    | ID_denyAdd
+    | ID_grantDiscloseOnError
+    | ID_denyDiscloseOnError 
+    | ID_grantRead
+    | ID_denyRead
+    | ID_grantRemove
+    | ID_denyRemove 
+    //-- permissions that may be used only in conjunction
+    //-- with the entry component
+    | ID_grantBrowse
+    | ID_denyBrowse
+    | ID_grantExport
+    | ID_denyExport
+    | ID_grantImport
+    | ID_denyImport
+    | ID_grantModify
+    | ID_denyModify
+    | ID_grantRename
+    | ID_denyRename
+    | ID_grantReturnDN
+    | ID_denyReturnDN
+    //-- permissions that may be used in conjunction
+    //-- with any component, except entry, of ProtectedItems
+    | ID_grantCompare
+    | ID_denyCompare
+    | ID_grantFilterMatch
+    | ID_denyFilterMatch
+    | ID_grantInvoke
+    | ID_denyInvoke
+    ;
+
+userClasses
+    :
+    ID_userClasses ( SP )+
+    OPEN_CURLY ( SP )*
+        (
+            userClass ( SP )*
+                ( SEP ( SP )* userClass ( SP )* )*
+        )?
+    CLOSE_CURLY
+    ;
+
+userClass
+    :
+    allUsers
+    | thisEntry 
+    | name
+    | userGroup
+    | subtree
+    ;
+
+allUsers
+    :
+    ID_allUsers
+    ;
+
+thisEntry
+    :
+    ID_thisEntry
+    ;
+
+name
+    :
+    ID_name ( SP )+ 
+        OPEN_CURLY ( SP )*
+            distinguishedName ( SP )*
+                ( SEP ( SP )* distinguishedName ( SP )*
+			)*
+        CLOSE_CURLY
+    ;
+
+userGroup
+    :
+    ID_userGroup ( SP )+ 
+        OPEN_CURLY ( SP )*
+            distinguishedName ( SP )*
+                ( SEP ( SP )* distinguishedName ( SP )* )*
+        CLOSE_CURLY
+    ;
+
+subtree
+    :
+    ID_subtree ( SP )+
+        OPEN_CURLY ( SP )*
+            subtreeSpecification ( SP )*
+                ( SEP ( SP )* subtreeSpecification ( SP )* )*
+        CLOSE_CURLY
+    ;
+
+userPermissions
+    :
+    ID_userPermissions ( SP )+
+        OPEN_CURLY ( SP )*
+            ( userPermission ( SP )*
+                ( SEP ( SP )* userPermission ( SP )* )*
+            )?
+        CLOSE_CURLY
+    ;
+
+userPermission
+     :
+     OPEN_CURLY ( SP )*
+         anyUserPermission ( SP )*
+             ( SEP ( SP )* anyUserPermission ( SP )* )*
+     CLOSE_CURLY
+     ;
+
+anyUserPermission
+    :
+    precedence
+    | protectedItems
+    | grantsAndDenials
+    ;
+
+subtreeSpecification
+    :
+    OPEN_CURLY ( SP )*
+        ( subtreeSpecificationComponent ( SP )*
+            ( SEP ( SP )* subtreeSpecificationComponent ( SP )* )* )?
+    CLOSE_CURLY
+    ;
+
+subtreeSpecificationComponent
+    :
+    ss_base
+    | ss_specificExclusions
+    | ss_minimum
+    | ss_maximum
+    ;
+
+ss_base
+    :
+    ID_base ( SP )+ distinguishedName
+    ;
+
+ss_specificExclusions
+    :
+    ID_specificExclusions ( SP )+ specificExclusions
+    ;
+
+specificExclusions
+    :
+    OPEN_CURLY ( SP )*
+        ( specificExclusion ( SP )*
+            ( SEP ( SP )* specificExclusion ( SP )* )*
+        )?
+    CLOSE_CURLY
+    ;
+
+specificExclusion
+    :
+    chopBefore | chopAfter
+    ;
+
+chopBefore
+    :
+    ID_chopBefore ( SP )* COLON ( SP )* distinguishedName
+    ;
+
+chopAfter
+    :
+    ID_chopAfter ( SP )* COLON ( SP )* distinguishedName
+    ;
+
+ss_minimum
+    :
+    ID_minimum ( SP )+ baseDistance
+    ;
+
+ss_maximum
+    :
+    ID_maximum ( SP )+ baseDistance
+    ;
+
+distinguishedName
+    :
+    SAFEUTF8STRING
+    ;
+
+baseDistance
+    :
+    INTEGER
+    ;
+
+oid
+    :
+    ( DESCR | NUMERICOID )
+    ;
+
+refinement
+    :
+    item | and | or | not
+    ;
+
+item
+    :
+    ID_item ( SP )* COLON ( SP )* oid
+    ;
+
+and
+    :
+    ID_and ( SP )* COLON ( SP )* refinements
+    ;
+
+or
+    :
+    ID_or ( SP )* COLON ( SP )* refinements
+    ;
+
+not
+    :
+    ID_not ( SP )* COLON ( SP )* refinements
+    ;
+
+refinements
+    :
+    OPEN_CURLY ( SP )*
+    (
+        refinement ( SP )*
+        ( SEP ( SP )* refinement ( SP )* )*
+    )? CLOSE_CURLY
+    ;
+
+    
+//  ----------------------------------------------------------------------------
+//  lexer class definition
+//  ----------------------------------------------------------------------------
+
+/**
+  * The parser's primary lexer.
+  *
+  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+  * @version $Rev$
+  */
+class AntlrACIItemCheckerLexer extends Lexer;
+
+
+//  ----------------------------------------------------------------------------
+//  lexer options
+//  ----------------------------------------------------------------------------
+
+options
+{
+    k = 2;
+    charVocabulary = '\3'..'\377';
+}
+
+
+//----------------------------------------------------------------------------
+// tokens
+//----------------------------------------------------------------------------
+
+tokens
+{
+    ID_identificationTag = "identificationTag";
+    ID_precedence = "precedence";
+    ID_FALSE = "FALSE";
+    ID_TRUE = "TRUE";
+    ID_none = "none";
+    ID_simple = "simple";
+    ID_strong = "strong";
+    ID_level = "level";
+    ID_basicLevels = "basicLevels";
+    ID_localQualifier = "localQualifier";
+    ID_signed = "signed";
+    ID_authenticationLevel = "authenticationLevel";
+    ID_itemOrUserFirst = "itemOrUserFirst";
+    ID_itemFirst = "itemFirst";
+    ID_userFirst = "userFirst";
+    ID_protectedItems = "protectedItems";
+    ID_classes = "classes";
+    ID_entry = "entry";
+    ID_allUserAttributeTypes = "allUserAttributeTypes";
+    ID_attributeType = "attributeType";
+    ID_allAttributeValues = "allAttributeValues";
+    ID_allUserAttributeTypesAndValues = "allUserAttributeTypesAndValues";
+    ID_selfValue = "selfValue";
+    ID_item = "item";
+    ID_and = "and";
+    ID_or = "or";
+    ID_not = "not";
+    ID_rangeOfValues = "rangeOfValues";
+    ID_maxValueCount = "maxValueCount";
+    ID_type = "type";
+    ID_maxCount = "maxCount";
+    ID_maxImmSub = "maxImmSub";
+    ID_restrictedBy = "restrictedBy";
+    ID_valuesIn = "valuesIn";
+    ID_userClasses = "userClasses";
+    ID_base = "base";
+    ID_specificExclusions = "specificExclusions";
+    ID_chopBefore = "chopBefore";
+    ID_chopAfter = "chopAfter";
+    ID_minimum = "minimum";
+    ID_maximum = "maximum";
+    ID_specificationFilter = "specificationFilter";
+    ID_grantsAndDenials = "grantsAndDenials";
+    ID_itemPermissions = "itemPermissions";
+    ID_userPermissions = "userPermissions";
+    ID_allUsers = "allUsers";
+    ID_thisEntry = "thisEntry";
+    ID_subtree = "subtree";
+    ID_name = "name";
+    ID_userGroup = "userGroup";
+
+    ID_grantAdd = "grantAdd"; // (0),
+    ID_denyAdd = "denyAdd";  // (1),
+    ID_grantDiscloseOnError = "grantDiscloseOnError";  // (2),
+    ID_denyDiscloseOnError = "denyDiscloseOnError";  // (3),
+    ID_grantRead = "grantRead";  // (4),
+    ID_denyRead = "denyRead";  // (5),
+    ID_grantRemove = "grantRemove";  // (6),
+    ID_denyRemove = "denyRemove";  // (7),
+    //-- permissions that may be used only in conjunction
+    //-- with the entry component
+    ID_grantBrowse = "grantBrowse";  // (8),
+    ID_denyBrowse = "denyBrowse";  // (9),
+    ID_grantExport = "grantExport";  // (10),
+    ID_denyExport = "denyExport";  // (11),
+    ID_grantImport = "grantImport";  // (12),
+    ID_denyImport = "denyImport";  // (13),
+    ID_grantModify = "grantModify";  // (14),
+    ID_denyModify = "denyModify";  // (15),
+    ID_grantRename = "grantRename";  // (16),
+    ID_denyRename = "denyRename";  // (17),
+    ID_grantReturnDN = "grantReturnDN";  // (18),
+    ID_denyReturnDN = "denyReturnDN";  // (19),
+    //-- permissions that may be used in conjunction
+    //-- with any component, except entry, of ProtectedItems
+    ID_grantCompare = "grantCompare";  // (20),
+    ID_denyCompare = "denyCompare";  // (21),
+    ID_grantFilterMatch = "grantFilterMatch";  // (22),
+    ID_denyFilterMatch = "denyFilterMatch";  // (23),
+    ID_grantInvoke = "grantInvoke";  // (24),
+    ID_denyInvoke = "denyInvoke";  // (25)
+}
+
+
+// ----------------------------------------------------------------------------
+//  lexer initialization
+// ----------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------
+// attribute description lexer rules from models
+// ----------------------------------------------------------------------------
+
+//  This is all messed up - could not figure out how to get antlr to represent
+//  the safe UTF-8 character set from RFC 3642 for production SafeUTF8Character
+
+protected SAFEUTF8CHAR :
+    '\u0001'..'\u0021' |
+    '\u0023'..'\u007F' |
+    '\u00c0'..'\u00d6' |
+    '\u00d8'..'\u00f6' |
+    '\u00f8'..'\u00ff' |
+    '\u0100'..'\u1fff' |
+    '\u3040'..'\u318f' |
+    '\u3300'..'\u337f' |
+    '\u3400'..'\u3d2d' |
+    '\u4e00'..'\u9fff' |
+    '\uf900'..'\ufaff' ;
+
+OPEN_CURLY : '{' ;
+
+CLOSE_CURLY : '}' ;
+
+SEP : ',' ;
+
+SP : ' ' | '\t' | '\n' { newline(); } | '\r' ;
+
+COLON : ':' ;
+
+protected DIGIT : '0' | LDIGIT ;
+
+protected LDIGIT : '1'..'9' ;
+
+protected ALPHA : 'A'..'Z' | 'a'..'z' ;
+
+protected INTEGER : DIGIT | ( LDIGIT ( DIGIT )+ ) ;
+
+protected HYPHEN : '-' ;
+
+protected NUMERICOID : INTEGER ( DOT INTEGER )+ ;
+
+protected DOT : '.' ;
+
+INTEGER_OR_NUMERICOID
+    :
+    ( INTEGER DOT ) => NUMERICOID
+    {
+        $setType( NUMERICOID );
+    }
+    |
+    INTEGER
+    {
+        $setType( INTEGER );
+    }
+    ;
+
+SAFEUTF8STRING : '"'! ( SAFEUTF8CHAR )* '"'! ;
+
+DESCR // THIS RULE ALSO STANDS FOR AN IDENTIFIER
+    :
+    ( "attributeValue" ( SP! )+ '{' ) =>
+      "attributeValue"! ( SP! )+ '{'! ( options { greedy = false; } : . )* '}'!
+      { $setType( ATTRIBUTE_VALUE_CANDIDATE ); }
+    | ( "rangeOfValues" ( SP! )+ '(' ) =>
+      "rangeOfValues"! ( SP! )+ '(' ( options { greedy = false; } : . )* ')'
+      { $setType( RANGE_OF_VALUES_CANDIDATE ); }
+    | ALPHA ( ALPHA | DIGIT | HYPHEN )*
+    ;

Added: directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemChecker.java
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemChecker.java?view=auto&rev=489128
==============================================================================
--- directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemChecker.java (added)
+++ directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ACIItemChecker.java Wed Dec 20 08:14:55 2006
@@ -0,0 +1,142 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.shared.ldap.aci;
+
+
+import java.io.StringReader;
+import java.text.ParseException;
+import java.util.Map;
+
+import org.apache.directory.shared.ldap.name.NameComponentNormalizer;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A reusable wrapper around the antlr generated parser for an ACIItem as
+ * defined by X.501. This class enables the reuse of the antlr parser/lexer pair
+ * without having to recreate them every time.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 437007 $
+ */
+public class ACIItemChecker
+{
+    /** the antlr generated parser being wrapped */
+    private ReusableAntlrACIItemChecker checker;
+
+    /** the antlr generated lexer being wrapped */
+    private ReusableAntlrACIItemCheckerLexer lexer;
+
+    private final boolean isNormalizing;
+
+
+    /**
+     * Creates a ACIItem parser.
+     */
+    public ACIItemChecker()
+    {
+        this.lexer = new ReusableAntlrACIItemCheckerLexer( new StringReader( "" ) );
+        this.checker = new ReusableAntlrACIItemChecker( lexer );
+
+        this.checker.init(); // this method MUST be called while we cannot do
+        // constructor overloading for antlr generated parser
+        this.isNormalizing = false;
+    }
+
+
+    /**
+     * Creates a normalizing ACIItem parser.
+     */
+    public ACIItemChecker(NameComponentNormalizer normalizer, Map oidsMap )
+    {
+        this.lexer = new ReusableAntlrACIItemCheckerLexer( new StringReader( "" ) );
+        this.checker = new ReusableAntlrACIItemChecker( lexer );
+
+        this.checker.setNormalizer( normalizer );
+        this.checker.init(); // this method MUST be called while we cannot do
+        // constructor overloading for antlr generated parser
+        this.isNormalizing = true;
+    }
+
+
+    /**
+     * Initializes the plumbing by creating a pipe and coupling the parser/lexer
+     * pair with it. param spec the specification to be parsed
+     */
+    private synchronized void reset( String spec )
+    {
+        StringReader in = new StringReader( spec );
+        this.lexer.prepareNextInput( in );
+        this.checker.resetState();
+    }
+
+
+    /**
+     * Parses an ACIItem without exhausting the parser.
+     * 
+     * @param spec
+     *            the specification to be parsed
+     * @return the specification bean
+     * @throws ParseException
+     *             if there are any recognition errors (bad syntax)
+     */
+    public synchronized void parse( String spec ) throws ParseException
+    {
+        if ( spec == null || spec.trim().equals( "" ) )
+        {
+            return;
+        }
+
+        reset( spec ); // reset and initialize the parser / lexer pair
+
+        try
+        {
+            this.checker.wrapperEntryPoint();
+        }
+        catch ( TokenStreamException e )
+        {
+            String msg = "Parser failure on ACIItem:\n\t" + spec;
+            msg += "\nAntlr exception trace:\n" + e.getMessage();
+            throw new ParseException( msg, 0 );
+        }
+        catch ( RecognitionException e )
+        {
+            String msg = "Parser failure on ACIItem:\n\t" + spec;
+            msg += "\nAntlr exception trace:\n" + e.getMessage();
+            throw new ParseException( msg, e.getColumn() );
+        }
+
+        return;
+    }
+
+
+    /**
+     * Tests to see if this parser is normalizing.
+     * 
+     * @return true if it normalizes false otherwise
+     */
+    public boolean isNormizing()
+    {
+        return this.isNormalizing;
+    }
+}

Added: directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemChecker.java
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemChecker.java?view=auto&rev=489128
==============================================================================
--- directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemChecker.java (added)
+++ directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemChecker.java Wed Dec 20 08:14:55 2006
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.shared.ldap.aci;
+
+
+
+import antlr.TokenStream;
+
+
+/**
+ * A reusable parser class extended from antlr generated parser for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr parser without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 437007 $
+ */
+class ReusableAntlrACIItemChecker extends AntlrACIItemChecker
+{
+    /**
+     * Creates a ReusableAntlrACIItemChecker instance.
+     */
+    public ReusableAntlrACIItemChecker( TokenStream lexer )
+    {
+        super( lexer );
+    }
+
+
+    /**
+     * Resets the state of an antlr parser.
+     */
+    public void resetState()
+    {
+        // no set method for this protected field.
+        this.traceDepth = 0;
+
+        this.getInputState().reset();
+    }
+}

Added: directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemCheckerLexer.java
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemCheckerLexer.java?view=auto&rev=489128
==============================================================================
--- directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemCheckerLexer.java (added)
+++ directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/aci/ReusableAntlrACIItemCheckerLexer.java Wed Dec 20 08:14:55 2006
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.shared.ldap.aci;
+
+
+import java.io.Reader;
+
+import antlr.CharBuffer;
+import antlr.LexerSharedInputState;
+
+
+/**
+ * A reusable lexer class extended from antlr generated lexer for an LDAP
+ * subtree specification as defined by <a
+ * href="http://www.faqs.org/rfcs/rfc3672.html"> RFC 3672</a>. This class
+ * enables the reuse of the antlr lexer without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ * 
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 437007 $
+ */
+class ReusableAntlrACIItemCheckerLexer extends AntlrACIItemCheckerLexer
+{
+    private boolean savedCaseSensitive;
+
+    private boolean savedCaseSensitiveLiterals;
+
+
+    /**
+     * Creates a ReusableAntlrACIItemCheckerLexer instance.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public ReusableAntlrACIItemCheckerLexer(Reader in)
+    {
+        super( in );
+        savedCaseSensitive = getCaseSensitive();
+        savedCaseSensitiveLiterals = getCaseSensitiveLiterals();
+    }
+
+
+    /**
+     * Resets the state of an antlr lexer and initializes it with new input.
+     * 
+     * @param in
+     *            the input to the lexer
+     */
+    public void prepareNextInput( Reader in )
+    {
+        CharBuffer buf = new CharBuffer( in );
+        LexerSharedInputState state = new LexerSharedInputState( buf );
+        this.setInputState( state );
+
+        this.setCaseSensitive( savedCaseSensitive );
+
+        // no set method for this protected field.
+        this.caseSensitiveLiterals = savedCaseSensitiveLiterals;
+    }
+}

Added: directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ACIItemChekerTest.java
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ACIItemChekerTest.java?view=auto&rev=489128
==============================================================================
--- directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ACIItemChekerTest.java (added)
+++ directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/aci/ACIItemChekerTest.java Wed Dec 20 08:14:55 2006
@@ -0,0 +1,250 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+
+package org.apache.directory.shared.ldap.aci;
+
+
+import org.apache.directory.shared.ldap.aci.ACIItemChecker;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Unit tests class for ACIItem checker (wrapper).
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 437007 $
+ */
+public class ACIItemChekerTest extends TestCase
+{
+
+    /** the ACIItem checker wrapper */
+    ACIItemChecker checker;
+
+
+    // /** holds multithreaded success value */
+    // boolean isSuccessMultithreaded = true;
+
+    /**
+     * Creates a ACIItemParserTest instance.
+     */
+    public ACIItemChekerTest()
+    {
+        super();
+        checker = new ACIItemChecker();
+    }
+
+
+    /**
+     * Creates a ACIItemParserTest instance.
+     */
+    public ACIItemChekerTest(String s)
+    {
+        super( s );
+        checker = new ACIItemChecker();
+    }
+
+
+    /**
+     * Tests the checker with an ACIItem of ItemFirst main component.
+     */
+    public void testItemFirst() throws Exception
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { entry  , attributeType { 1.2.3    , ou }  , "
+            + " attributeValue { ou=people  , cn=Ersin  }  , rangeOfValues (cn=ErsinEr) , "
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        checker.parse( spec );
+    }
+
+
+    /**
+     * Tests the checker with an ACIItem of UserFirst main component.
+     */
+    public void testUserFirst() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    public void testAllowAddAllUsers() throws Exception
+    {
+        String spec = "{ identificationTag \"addAci\", " + "precedence 14, " + "authenticationLevel none, "
+            + "itemOrUserFirst userFirst: { " + "userClasses { allUsers }, "
+            + "userPermissions { { protectedItems {entry}, " + "grantsAndDenials { grantAdd } } } } }";
+
+        checker.parse( spec );
+    }
+
+
+    public void testCombo() throws Exception
+    {
+        String spec = "{ identificationTag \"addAci\", " + "precedence 14, " + "authenticationLevel none, "
+            + "itemOrUserFirst userFirst: { " + "userClasses { allUsers, name { \"ou=blah\" } }, "
+            + "userPermissions { { protectedItems {entry}, " + "grantsAndDenials { grantAdd } } } } }";
+
+        checker.parse( spec );
+    }
+
+
+    public void testOrderOfProtectedItemsDoesNotMatter() throws Exception
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { attributeType { 1.2.3    , ou }, entry , "
+            + " rangeOfValues (cn=ErsinEr) , attributeValue { ou=people  , cn=Ersin  },"
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        checker.parse( spec );
+    }
+
+
+    public void testOrderOfUserClassesDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  name { \"ou=people,cn=ersin\" }, allUsers, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    public void testItemPermissionComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ protectedItems  { attributeType { 1.2.3    , ou }, entry , "
+            + " rangeOfValues (cn=ErsinEr) , attributeValue { ou=people  , cn=Ersin  },"
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  , "
+            + "itemPermissions { { grantsAndDenials  {  denyCompare  , grantModify }, userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } } }}";
+
+        checker.parse( spec );
+    }
+
+
+    public void testUserPermissionComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { grantsAndDenials { grantBrowse }, protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    public void testOrderOfMainACIComponentsDoesNotMatter() throws Exception
+    {
+        String spec = "{   itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } } }, "
+            + " identificationTag \"id2\"   , authenticationLevel none, precedence 14 }   ";
+
+        checker.parse( spec );
+    }
+
+
+    public void testUserFirstComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } }, userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + "minimum  1, maximum   2 } } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    public void testItemFirstComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = " {  identificationTag  \"id1\" , precedence 114  , authenticationLevel simple  , "
+            + "itemOrUserFirst itemFirst  :{ itemPermissions { { userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } },"
+            + "{ precedence 10, userClasses {allUsers  , userGroup { \"1.2=y,z=t\"  , \"a=b,c=d\" } "
+            + " , subtree { { base \"ou=people\" } } }   , grantsAndDenials  {  denyCompare  , grantModify } } },protectedItems  { entry  , attributeType { 1.2.3    , ou }  , "
+            + " attributeValue { ou=people  , cn=Ersin  }  , rangeOfValues (cn=ErsinEr) , "
+            + "classes and : { item: xyz , or:{item:X,item:Y}   }}  " + " }}";
+
+        checker.parse( spec );
+    }
+
+
+    public void testRestrictedValueComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\"}, { base \"ou=ORGANIZATIONUNIT\"," + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , "
+            + "maxValueCount { { type 10.11.12, maxCount 10 }, { maxCount 20, type 11.12.13  } } "
+            + " }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    public void testMaxValueCountComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\"," + "minimum  1, maximum   2 } } }  , "
+            + "userPermissions { { protectedItems{ entry  , "
+            + "restrictedBy { { type 10.11.12, valuesIn ou }, { valuesIn cn, type 11.12.13  } } "
+            + " }  , grantsAndDenials { grantBrowse } } } }  }   ";
+
+        checker.parse( spec );
+    }
+
+
+    public void testSubtreeSpecificationComponentsOrderDoesNotMatter() throws Exception
+    {
+        String spec = "{ identificationTag \"id2\"   , precedence 14, authenticationLevel none  , "
+            + "itemOrUserFirst userFirst:  { userPermissions { { protectedItems{ entry  , attributeType { cn  , ou }  , attributeValue {x=y,m=n,k=l} , "
+            + "rangeOfValues (cn=ErsinEr) }  , grantsAndDenials { grantBrowse } } }, userClasses {  allUsers  , name { \"ou=people,cn=ersin\" }, "
+            + "subtree {{ minimum 7, maximum 9, base \"ou=system\" }, { base \"ou=ORGANIZATIONUNIT\","
+            + " maximum   2, minimum  1 } } }  }  }   ";
+
+        checker.parse( spec );
+    }
+}