directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From akaras...@apache.org
Subject svn commit: r240354 - in /directory/shared/ldap/trunk: ./ common/src/antlr/ common/src/java/org/apache/ldap/common/subtree/ common/src/test/org/apache/ldap/common/subtree/ common/src/test/resources/
Date Fri, 26 Aug 2005 22:10:17 GMT
Author: akarasulu
Date: Fri Aug 26 15:10:09 2005
New Revision: 240354

URL: http://svn.apache.org/viewcvs?rev=240354&view=rev
Log:
Committing patches from Ersin Er to add a proper subtree specification parser.
His JIRA issue with the attached patch applied is DIRLDAP-49 and can be found 
here:

	http://issues.apache.org/jira/browse/DIRLDAP-49

Added:
    directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/ReusableAntlrSubtreeSpecificationLexer.java
    directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/ReusableAntlrSubtreeSpecificationParser.java
    directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/SubtreeSpecificationParser.java
    directory/shared/ldap/trunk/common/src/test/org/apache/ldap/common/subtree/SubtreeSpecificationParserTest.java
    directory/shared/ldap/trunk/common/src/test/resources/
    directory/shared/ldap/trunk/common/src/test/resources/log4j.properties
Removed:
    directory/shared/ldap/trunk/common/src/test/org/apache/ldap/common/subtree/SubtreeParserTest.java
Modified:
    directory/shared/ldap/trunk/common/src/antlr/subtree-specification.g
    directory/shared/ldap/trunk/project.xml

Modified: directory/shared/ldap/trunk/common/src/antlr/subtree-specification.g
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/trunk/common/src/antlr/subtree-specification.g?rev=240354&r1=240353&r2=240354&view=diff
==============================================================================
--- directory/shared/ldap/trunk/common/src/antlr/subtree-specification.g (original)
+++ directory/shared/ldap/trunk/common/src/antlr/subtree-specification.g Fri Aug 26 15:10:09
2005
@@ -1,32 +1,43 @@
 header
 {
 /*
- * Copyright 2002-2004 The Apache Software Foundation.
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
  *
- * 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.
  */
 
-/*
- * Keep the semicolon right next to org.apache.ldap.common.filter or else there
- * will be a bug that comes into the foreground in the new antlr release.
- */
+
 package org.apache.ldap.common.subtree;
 
+import java.util.Set;
+import java.util.HashSet;
+import java.util.ArrayList;
 
 import javax.naming.Name;
 import javax.naming.NamingException;
-import org.apache.ldap.common.name.LdapName;
 
+import org.apache.ldap.common.name.DnParser;
+import org.apache.ldap.common.filter.ExprNode;
+import org.apache.ldap.common.filter.LeafNode;
+import org.apache.ldap.common.filter.SimpleNode;
+import org.apache.ldap.common.filter.BranchNode;
+import org.apache.ldap.common.filter.AbstractExprNode;
+import org.apache.ldap.common.subtree.SubtreeSpecification;
+import org.apache.ldap.common.subtree.SubtreeSpecificationModifier;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 }
 
 
@@ -38,41 +49,330 @@
  * The antlr generated subtree specification parser.
  *
  * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
- * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
  */
 class AntlrSubtreeSpecificationParser extends Parser;
 
 
 // ----------------------------------------------------------------------------
-// parser productions
+// parser options
 // ----------------------------------------------------------------------------
 
+options
+{
+    k = 3;
+
+    defaultErrorHandler = false;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser initialization
+// ----------------------------------------------------------------------------
 
-subtreeSpecification returns [SubtreeSpecification spec]
 {
-    spec = null;
+    private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationParser.class
);
+    private final DnParser dnParser = createDnParser();
+    
+    private Set chopBeforeExclusions = new HashSet();
+    private Set chopAfterExclusions = new HashSet();
+
+    SubtreeSpecificationModifier ssModifier = null;
+
+    /**
+     * Creates a subordinate DnParser for parsing LocalNames.
+     *
+     * @return the DnParser to be used for parsing LocalNames
+     */
+    private DnParser createDnParser()
+    {
+        try
+        {
+            return new DnParser();
+        }
+        catch ( NamingException e )
+        {
+            String msg = "Failed to initialize the subordinate DnParser for this AntlrSubtreeSpecificationParser";
 
-    SubtreeSpecificationModifier modifier = new SubtreeSpecificationModifier();
+            // We throw a NPE since this variable cannot be null for proper operation
+            // so we can catch the null pointer before the dnParser is even used.
+
+            throw new NullPointerException( "dnParser is null: " + msg );
+        }
+    }
 }
-    :
+
+
+// ----------------------------------------------------------------------------
+// parser productions
+// ----------------------------------------------------------------------------
+
+wrapperEntryPoint returns [SubtreeSpecification ss]
+{
+    log.debug( "entered wrapperEntryPoint()" );
+    ss = null;
+    SubtreeSpecification tempSs = null;
+} :
+    tempSs=subtreeSpecification "end"
+    {
+        ss = tempSs;
+    }
+    ;
+
+
+subtreeSpecification returns [SubtreeSpecification ss]
+{
+    log.debug( "entered subtreeSpecification()" );
+    // clear out ss and ssModifier in case something is left from the last parse
+    ss = null;
+    ssModifier = new SubtreeSpecificationModifier();
+} :
+    LBRACKET
+        ( SP ss_base )?
+        ( SEP SP ss_specificExclusions )?
+        ( SEP SP ss_minimum )?
+        ( SEP SP ss_maximum )?
+        ( SEP SP ss_specificationFilter )?
+    SP RBRACKET
+    {
+        ss = ssModifier.getSubtreeSpecification();
+    }
+    ;
+
+
+ss_base
+{
+    log.debug( "entered ss_base()" );
+    Name base = null;
+} :
+    "base" (SP)+ base=localName
+    {
+        ssModifier.setBase( base );
+    }
+    ;
+
+
+ss_specificExclusions
+{
+    log.debug( "entered ss_specificExclusions()" );
+} :
+    "specificExclusions" ( SP )+ specificExclusions
+    {
+        ssModifier.setChopBeforeExclusions( chopBeforeExclusions );
+        ssModifier.setChopAfterExclusions( chopAfterExclusions );
+    }
+    ;
+
+
+specificExclusions
+{
+    log.debug( "entered specificExclusions()" );
+} :
+    LBRACKET
+        ( SP specificExclusion
+            (SEP SP specificExclusion)*
+        )?
+    SP RBRACKET
+    ;
+
+
+specificExclusion
+{
+    log.debug( "entered specificExclusion()" );
+} :
+    chopBefore | chopAfter
+    ;
+
+
+chopBefore
+{
+    log.debug( "entered chopBefore()" );
+    Name chopBeforeExclusion = null;
+} :
+    "chopBefore" COLON chopBeforeExclusion=localName
+    {
+        chopBeforeExclusions.add( chopBeforeExclusion );
+    }
+    ;
+
+
+chopAfter
+{
+    log.debug( "entered chopAfter()" );
+    Name chopAfterExclusion = null;
+} :
+    "chopAfter" COLON chopAfterExclusion=localName
+    {
+        chopAfterExclusions.add( chopAfterExclusion );
+    }
+    ;
+
+
+ss_minimum
+{
+    log.debug( "entered ss_minimum()" );
+    int minimum = 0;
+} :
+    "minimum" ( SP )+ minimum=baseDistance
+    {
+        ssModifier.setMinBaseDistance( minimum );
+    }
+    ;
+
+
+ss_maximum
+{
+    log.debug( "entered ss_maximum()" );
+    int maximum = 0;
+} :
+    "maximum" ( SP )+ maximum=baseDistance
+    {
+        ssModifier.setMaxBaseDistance( maximum );
+    }
+    ;
+
+
+ss_specificationFilter
+{
+    log.debug( "entered ss_specificationFilter()" );
+    ExprNode theRefinement = null;
+}:
+    ( "specificationFilter" ( SP )+ theRefinement=refinement
+    {
+        ssModifier.setRefinement( theRefinement );
+    } )?
+    ;
+
+
+localName returns [Name name] 
+{
+    log.debug( "entered localName()" );
+    name = null;
+} :
+    token:DQUOTEDSTRING
+    {
+        name = dnParser.parse( token.getText() );
+    }
+    ;
+    exception
+    catch [Exception e]
+    {
+        throw new RecognitionException( "dnParser failed." + e.getMessage() );
+    }
+
+
+baseDistance returns [int distance]
+{
+    log.debug( "entered baseDistance()" );
+    distance = 0;
+} :
+    token:NUMBER
+    {
+        distance = Integer.parseInt( token.getText() );
+    }
+    ;
+
+
+refinement returns [ExprNode node]
+{
+    log.debug( "entered refinement()" );
+    node = null;
+} :
+    node=item | node=and | node=or | node=not
+    ;
+
+
+item returns [LeafNode node]
+{
+    log.debug( "entered item()" );
+    node = null;
+    String oid = null;
+} :
+    "item" COLON oid=objectIdentifier
+    {
+        node = new SimpleNode( "objectClass" , oid , AbstractExprNode.EQUALITY );
+    }
+    ;
+
+
+objectIdentifier returns [String oid]
+{
+    oid = null;
+} :
+    token1:DESCR
+    {
+        oid = token1.getText();
+    }
+    |
+    token2:NUMERICOID
+    {
+        oid = token2.getText();
+    }
+    ;
+
+
+and returns [BranchNode node]
+{
+    log.debug( "entered and()" );
+    node = null;
+    ArrayList children = null; 
+} :
+    "and" COLON children=refinements
+    {
+        node = new BranchNode( AbstractExprNode.AND , children );
+    }
+    ;
+
+
+or returns [BranchNode node]
+{
+    log.debug( "entered or()" );
+    node = null;
+    ArrayList children = null; 
+} :
+    "or" COLON children=refinements
+    {
+        node = new BranchNode( AbstractExprNode.OR , children );
+    }
+    ;
+
+
+not returns [BranchNode node]
+{
+    log.debug( "entered not()" );
+    node = null;
+    ArrayList children = null;
+} :
+    "not" COLON children=refinements
+    {
+        node = new BranchNode( AbstractExprNode.NOT , children );
+    }
+    ;
+
+
+refinements returns [ArrayList children]
+{
+    log.debug( "entered refinements()" );
+    children = null;
+    ExprNode child = null;
+    ArrayList tempChildren = new ArrayList();
+} :
     LBRACKET
-    (
-        BASE rdn:LOCALNAME
+    ( SP
+        child=refinement
         {
-            String quoted = rdn.getText();
-            try
-            {
-                modifier.setBase( new LdapName( quoted.substring( 1, quoted.length() - 1
) ) );
-            }
-            catch ( NamingException e )
-            {
-                throw new RecognitionException( "LdapName parse failed on base." );
-            }
+            tempChildren.add( child );
         }
-    )?
-    ( SP )*
-    RBRACKET
-    { spec = modifier.getSubtreeSpecification(); };
+        ( SEP SP child=refinement
+        {
+            tempChildren.add( child );
+        } )*
+    )? SP RBRACKET
+    {
+        children = tempChildren;
+    }
+    ;
 
 
 // ----------------------------------------------------------------------------
@@ -83,7 +383,8 @@
  * The parser's primary lexer.
  *
  * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
- * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
  */
 class AntlrSubtreeSpecificationLexer extends Lexer;
 
@@ -94,19 +395,20 @@
 
 options
 {
-	k=5;
+    k = 3;
+
+    charVocabulary = '\u0001'..'\u0127';
 
-	charVocabulary='\u0001'..'\u0127';
+    testLiterals = false;
 }
 
 
-// ----------------------------------------------------------------------------
-// lexer class members
-// ----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+// lexer initialization
+//----------------------------------------------------------------------------
 
 {
-    /** the selector key used by this class of lexer */
-    public static final String SELECTOR_KEY = "refinementLexer";
+    private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationLexer.class
);
 }
 
 
@@ -114,45 +416,55 @@
 // attribute description lexer rules from models
 // ----------------------------------------------------------------------------
 
+SP : ' ' ;
 
-SP: ' ';
-
-LBRACKET: '{' ( SP )*;
+COLON : ':' { log.debug( "matched COLON(':')" ); } ;
 
-RBRACKET: '}';
+LBRACKET : '{' { log.debug( "matched LBRACKET('{')" ); } ;
 
-DQUOTE: '"';
+RBRACKET : '}' { log.debug( "matched RBRACKET('}')" ); } ;
 
-COMMA: ',';
+DQUOTE : '"' { log.debug( "matched DQUOTE('\"')" ); } ;
 
-OR: "or:";
+SEP : ',' { log.debug( "matched SEP(',')" ); } ;
 
-AND: "and:";
+DQUOTEDSTRING : DQUOTE! ( SAFEUTF8CHAR )* DQUOTE! { log.debug( "matched DQUOTEDSTRING: \""
+ getText() + "\"" ); } ;
 
-NOT: "not:";
+DESCR options { testLiterals = true; } : ALPHA ( ALPHA | DIGIT | '-' )* { log.debug( "matched
DESCR" ); } ;
 
-ITEM: "item:";
+// This rule is required to prevent nondeterminism problem caused by NUMBER and NUMERICOID
rules.
 
-BASE: "base" ( SP )+ ;
+NUMBER_OR_NUMERICOID
+    :
+    ( NUMBER DOT ) => NUMERICOID
+    {
+        $setType(NUMERICOID);
+    }
+    |
+    NUMBER
+    {
+        $setType(NUMBER);
+    }
+    ;
 
-protected DIGIT: '0' | LDIGIT;
+protected NUMBER: DIGIT | ( LDIGIT ( DIGIT )+ ) { log.debug( "matched NUMBER: " + getText()
); } ;
 
-protected LDIGIT: '1'..'9';
+protected NUMERICOID: NUMBER ( DOT NUMBER )+ { log.debug( "matched NUMERICOID: " + getText()
); } ;
 
-protected ALPHA: 'A'..'Z' | 'a'..'z';
+protected DOT: '.' ;
 
-protected NUMBER: DIGIT | ( LDIGIT ( DIGIT )+ );
+protected DIGIT: '0' | LDIGIT ;
 
-protected NUMERICOID: NUMBER ( '.' NUMBER )+;
+protected LDIGIT: '1'..'9' ;
 
-protected DESCR: ALPHA ( ALPHA | DIGIT | '-' )*;
+protected ALPHA: 'A'..'Z' | 'a'..'z' ;
 
-// this is all messed up - could not figure out how to get antlr to represent
+// 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' |
+    '\u0001'..'\u0021' |
+    '\u0023'..'\u007F' |
     '\u00c0'..'\u00d6' |
     '\u00d8'..'\u00f6' |
     '\u00f8'..'\u00ff' |
@@ -162,8 +474,3 @@
     '\u3400'..'\u3d2d' |
     '\u4e00'..'\u9fff' |
     '\uf900'..'\ufaff' ;
-
-OID: DESCR | NUMERICOID;
-
-LOCALNAME: DQUOTE ( SAFEUTF8CHAR )* DQUOTE ;
-

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

Added: directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/ReusableAntlrSubtreeSpecificationParser.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/ReusableAntlrSubtreeSpecificationParser.java?rev=240354&view=auto
==============================================================================
--- directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/ReusableAntlrSubtreeSpecificationParser.java
(added)
+++ directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/ReusableAntlrSubtreeSpecificationParser.java
Fri Aug 26 15:10:09 2005
@@ -0,0 +1,58 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+
+package org.apache.ldap.common.subtree;
+
+
+import antlr.TokenStream;
+
+
+/**
+ * A reusable parser class extended from antlr generated parser for an LDAP
+ * subtree specification as defined by <a href="http://www.faqs.org/rfcs/rfc3672.html">
+ * RFC 3672</a>.  This class enables the reuse of the antlr parser without having to
+ * recreate the it every time as stated in 
+ * <a href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class ReusableAntlrSubtreeSpecificationParser extends AntlrSubtreeSpecificationParser
+{
+    /**
+     * Creates a ReusableAntlrSubtreeSpecificationParser instance.
+     */
+    public ReusableAntlrSubtreeSpecificationParser( TokenStream lexer )
+    {
+        super( lexer );
+    }
+
+    
+    /**
+     * Resets the state of an antlr parser.
+     */
+    public void resetState()
+    {
+        // no set method for this protected field.
+        this.traceDepth = 0;
+        
+        this.getInputState().reset();
+    }
+}

Added: directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/SubtreeSpecificationParser.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/SubtreeSpecificationParser.java?rev=240354&view=auto
==============================================================================
--- directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/SubtreeSpecificationParser.java
(added)
+++ directory/shared/ldap/trunk/common/src/java/org/apache/ldap/common/subtree/SubtreeSpecificationParser.java
Fri Aug 26 15:10:09 2005
@@ -0,0 +1,109 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+package org.apache.ldap.common.subtree;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.text.ParseException;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+
+
+/**
+ * A reusable wrapper around the antlr generated parser for an LDAP subtree
+ * specification as defined by <a href="http://www.faqs.org/rfcs/rfc3672.html">
+ * RFC 3672</a>.  This class enables the reuse of the antlr parser/lexer pair
+ * without having to recreate the pair every time.
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class SubtreeSpecificationParser
+{
+    /** the antlr generated parser being wrapped */
+    private ReusableAntlrSubtreeSpecificationParser parser;
+    /** the antlr generated lexer being wrapped */
+    private ReusableAntlrSubtreeSpecificationLexer lexer;
+
+
+    /**
+     * Creates a subtree specification parser.
+     */
+    public SubtreeSpecificationParser()
+    {
+        StringReader in = new StringReader(""); // place holder for the first input
+        this.lexer = new ReusableAntlrSubtreeSpecificationLexer( in );
+        this.parser = new ReusableAntlrSubtreeSpecificationParser( lexer );
+    }
+
+
+    /**
+     * 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 + "end" ); // append end of input token
+        this.lexer.prepareNextInput(in);
+        this.parser.resetState();
+    }
+
+
+    /**
+     * Parses a subtree specification without exhausting the parser.
+     *
+     * @param spec the specification to be parsed
+     * @return the specification bean
+     * @throws ParseException if there are any recognition errors (bad syntax)
+     * @throws IOException if there is a problem with underlying streams
+     */
+    public synchronized SubtreeSpecification parse( String spec ) throws ParseException,
IOException
+    {
+        SubtreeSpecification ss = null;
+
+        if ( spec == null || spec.trim().equals( "" ) )
+        {
+            return null;
+        }
+        
+        reset(spec); // reset and initialize the parser / lexer pair
+
+        try
+        {
+            ss = this.parser.wrapperEntryPoint();
+        }
+        catch ( TokenStreamException e )
+        {
+            String msg = "Parser failure on subtree specification:\n\t" + spec ;
+            msg += "\nAntlr exception trace:\n" + e.getMessage();
+            throw new ParseException( msg, 0 );
+        }
+        catch ( RecognitionException e )
+        {
+            String msg = "Parser failure on subtree specification:\n\t" + spec ;
+            msg += "\nAntlr exception trace:\n" + e.getMessage();
+            throw new ParseException( msg, e.getColumn() );
+        }   
+
+        return ss;
+    }
+}

Added: directory/shared/ldap/trunk/common/src/test/org/apache/ldap/common/subtree/SubtreeSpecificationParserTest.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/trunk/common/src/test/org/apache/ldap/common/subtree/SubtreeSpecificationParserTest.java?rev=240354&view=auto
==============================================================================
--- directory/shared/ldap/trunk/common/src/test/org/apache/ldap/common/subtree/SubtreeSpecificationParserTest.java
(added)
+++ directory/shared/ldap/trunk/common/src/test/org/apache/ldap/common/subtree/SubtreeSpecificationParserTest.java
Fri Aug 26 15:10:09 2005
@@ -0,0 +1,484 @@
+/*
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+
+package org.apache.ldap.common.subtree;
+
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.ldap.common.filter.AbstractExprNode;
+import org.apache.ldap.common.filter.BranchNode;
+import org.apache.ldap.common.filter.SimpleNode;
+import org.apache.ldap.common.name.LdapName;
+import org.apache.ldap.common.subtree.SubtreeSpecification;
+
+
+/**
+ * Unit tests class for Subtree Specification parser (wrapper).
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class SubtreeSpecificationParserTest extends TestCase
+{
+    /** A valid empty specification with single white space between brackets */
+    private static final String EMPTY_SPEC =
+        "{ }";
+    
+    /** An invalid empty specification with two white spaces between brackets */
+    private static final String INVALID_EMPTY_SPEC_WITH_EXTRA_WS =
+        "{  }";
+
+    /** A valid specification only with base set */
+    private static final String SPEC_WITH_BASE =
+        "{ base \"ou=system\" }";
+    
+    /** An invalid specification with missing white space and base set */
+    private static final String INVALID_SPEC_WITH_BASE_AND_MISSING_WS =
+        "{ base\"ou=system\"}";
+    
+    /** An invalid specification with extra whitespace and base set */
+    private static final String INVALID_SPEC_WITH_BASE_AND_EXTRA_WS =
+        "{ base ou=system\" }    ";
+
+    /** A valid specification with some specific exclusions set */
+    private static final String SPEC_WITH_SPECIFICEXCLUSIONS =
+        "{, specificExclusions { chopAfter:\"ef=gh\", chopBefore:\"ab=cd\" } }";
+    
+    /** A valid specification with empty specific exclusions set */
+    private static final String SPEC_WITH_EMPTY_SPECIFICEXCLUSIONS =
+        "{, specificExclusions { } }";
+
+    /** A valid specification with minimum and maximum set */
+    private static final String SPEC_WITH_MINIMUM_AND_MAXIMUM =
+        "{, minimum 1, maximum 2 }";
+    
+    /** A valid specification with base and minimum and maximum set */
+    private static final String SPEC_WITH_BASE_AND_MINIMUM_AND_MAXIMUM =
+        "{ base \"ou=ORGANIZATION UNIT\", minimum  1, maximum   2 }";
+     
+    /** A valid specification with base and specific exclusions and minimum and maximum set
*/
+    private static final String SPEC_WITH_BASE_AND_SPECIFICEXCLUSIONS_AND_MINIMUM_AND_MAXIMUM
=
+        "{ base \"ou=people\", specificExclusions { chopBefore:\"x=y\"" +
+        ", chopAfter:\"k=l\", chopBefore:\"y=z\", chopAfter:\"l=m\" }, minimum   7, maximum
77 }";
+
+    /** A valid specification with refinement set */
+    private static final String SPEC_WITH_REFINEMENT =
+        "{ base \"ou=system\", specificationFilter and:{ and:{ item:1.2.3" +
+        ", or:{ item:4.5.6, item:person-7 } }, not:{ item:10.11.12 } } }";
+    
+    /** A valid specification with base and an empty refinement set */
+    private static final String SPEC_WITH_BASE_AND_EMPTY_REFINEMENT =
+        "{ base \"ou=system\", specificationFilter and:{ } }";
+    
+    /** A valid specification with ALL IN ONE */
+    private static final String SPEC_WITH_ALL_IN_ONE =
+        "{ base    \"ou=departments\"" +
+        ", specificExclusions { chopBefore:\"x=y\", chopAfter:\"k=l\", chopBefore:\"y=z\",
chopAfter:\"l=m\" }" +
+        ", minimum 7, maximum   77" + 
+        ", specificationFilter     and:{ and:{ item:1.2.3, or:{ item:4.5.6, item:7.8.9 }
}, not:{ item:10.11.12 } } }";
+    
+    private static final String INVALID_SPEC_WITH_WRONG_COMPONENT_ORDER =
+        "{ base \"ou=system\", minimum 3, specificExclusions { chopBefore:\"x=y\" } }";
+
+    private static final String INVALID_SILLY_THING =
+        "How much wood would a wood chuck chuck if a wood chuck would chuck wood?";
+
+    
+    /** the ss parser wrapper */
+    SubtreeSpecificationParser parser;
+    
+    /** holds multithreaded success value */
+    boolean isSuccessMultithreaded = true;
+
+
+    /**
+     * Creates a SubtreeSpecificationParserTest instance.
+     */
+    public SubtreeSpecificationParserTest()
+    {
+        super();
+        parser = new SubtreeSpecificationParser();
+    }
+
+    
+    /**
+     * Creates a SubtreeSpecificationParserTest instance.
+     */
+    public SubtreeSpecificationParserTest( String s )
+    {
+        super( s );
+        parser = new SubtreeSpecificationParser();
+    }
+
+
+    /**
+     * Tests the parser with a valid empty specification.
+     */    
+    public void testEmptySpec() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( EMPTY_SPEC );
+        assertNotNull( ss );
+
+        // try a second time
+        ss = parser.parse( EMPTY_SPEC );
+        assertNotNull( ss );
+
+        // try a third time
+        ss = parser.parse( EMPTY_SPEC );
+        assertNotNull( ss );
+    }
+
+
+    /**
+     * Tests the parser with an invalid empty specification with extra white spaces.
+     */
+    public void testInvalidEmptySpecWithExtraWS() throws Exception
+    {
+        try
+        {
+           SubtreeSpecification ss = parser.parse( INVALID_EMPTY_SPEC_WITH_EXTRA_WS );
+           fail( "testInvalidEmptySpecWithExtraWS() should never come here..." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+        catch ( IOException e )
+        {
+            assertNotNull( e );
+        }
+    }
+    
+    
+    /**
+     * Tests the parser with a valid specification with base set.
+     */
+    public void testSpecWithBase() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE );
+        assertNotNull( ss );
+        
+        assertEquals( "ou=system" , ss.getBase().toString() );
+    }
+    
+    
+    /**
+     * Tests the parser with an invalid specification with missing white spaces and base
set.
+     */
+    public void testInvalidSpecWithBaseAndMissingWS() throws Exception
+    {
+        try
+        {
+           SubtreeSpecification ss = parser.parse( INVALID_SPEC_WITH_BASE_AND_MISSING_WS
);
+           fail( "testInvalidSpecWithBaseAndMissingWS() should never come here..." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+        catch ( IOException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    /**
+     * Tests the parser with an invalid specification with extra white spaces and base set.
+     */
+    public void testInvalidSpecWithBaseAndExtraWS() throws Exception
+    {
+        try
+        {
+           SubtreeSpecification ss = parser.parse( INVALID_SPEC_WITH_BASE_AND_EXTRA_WS );
+           fail( "testInvalidSpecWithBaseAndExtraWS() should never come here..." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+        catch ( IOException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with some specific exclusions set.
+     */
+    public void testSpecWithSpecificExclusions() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_SPECIFICEXCLUSIONS );
+        assertFalse( ss.getChopBeforeExclusions().isEmpty() );
+        assertFalse( ss.getChopAfterExclusions().isEmpty() );
+        assertTrue( ss.getChopBeforeExclusions().contains( new LdapName( "ab=cd" ) ) );
+        assertTrue( ss.getChopAfterExclusions().contains( new LdapName( "ef=gh" ) ) );
+
+        // try a second time
+        ss = parser.parse( SPEC_WITH_SPECIFICEXCLUSIONS );
+        assertFalse( ss.getChopBeforeExclusions().isEmpty() );
+        assertFalse( ss.getChopAfterExclusions().isEmpty() );
+        assertTrue( ss.getChopBeforeExclusions().contains( new LdapName( "ab=cd" ) ) );
+        assertTrue( ss.getChopAfterExclusions().contains( new LdapName( "ef=gh" ) ) );
+
+        // try a third time
+        ss = parser.parse( SPEC_WITH_SPECIFICEXCLUSIONS );
+        assertFalse( ss.getChopBeforeExclusions().isEmpty() );
+        assertFalse( ss.getChopAfterExclusions().isEmpty() );
+        assertTrue( ss.getChopBeforeExclusions().contains( new LdapName( "ab=cd" ) ) );
+        assertTrue( ss.getChopAfterExclusions().contains( new LdapName( "ef=gh" ) ) );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with an empty specific exclusions set.
+     */
+    public void testSpecWithEmptySpecificExclusions() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_EMPTY_SPECIFICEXCLUSIONS );
+        assertNotNull( ss );
+        
+        assertTrue( ss.getChopBeforeExclusions().isEmpty() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with minimum and maximum set.
+     */
+    public void testSpecWithMinimumAndMaximum() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_MINIMUM_AND_MAXIMUM );
+        assertEquals( 1 , ss.getMinBaseDistance() );
+        assertEquals( 2 , ss.getMaxBaseDistance() );
+
+        // try a second time
+        ss = parser.parse( SPEC_WITH_MINIMUM_AND_MAXIMUM );
+        assertEquals( 1 , ss.getMinBaseDistance() );
+        assertEquals( 2 , ss.getMaxBaseDistance() );
+
+        // try a third time
+        ss = parser.parse( SPEC_WITH_MINIMUM_AND_MAXIMUM );
+        assertEquals( 1 , ss.getMinBaseDistance() );
+        assertEquals( 2 , ss.getMaxBaseDistance() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base and minimum and maximum set.
+     */
+    public void testWithBaseAndMinimumAndMaximum() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE_AND_MINIMUM_AND_MAXIMUM );
+        
+        assertEquals( new LdapName( "ou=ORGANIZATION UNIT" ) , ss.getBase() );
+        assertEquals( 1 , ss.getMinBaseDistance());
+        assertEquals( 2 , ss.getMaxBaseDistance());
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with base and specific exclusions and
minimum and maximum set.
+     */
+    public void testSpecWithBaseAndSpecificExclusionsAndMinimumAndMaximum() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE_AND_SPECIFICEXCLUSIONS_AND_MINIMUM_AND_MAXIMUM
);
+        assertNotNull ( ss );
+        
+        assertEquals ( "ou=people", ss.getBase().toString() );
+        assertTrue ( ss.getChopBeforeExclusions().contains( new LdapName( "x=y" ) ) );
+        assertTrue ( ss.getChopBeforeExclusions().contains( new LdapName( "y=z" ) ) );
+        assertTrue ( ss.getChopAfterExclusions().contains( new LdapName( "k=l" ) ) );
+        assertTrue ( ss.getChopAfterExclusions().contains( new LdapName( "l=m" ) ) );
+        assertEquals ( 7 , ss.getMinBaseDistance() );
+        assertEquals ( 77 , ss.getMaxBaseDistance() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with refinement set.
+     */
+    public void testSpecWithRefinement() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_REFINEMENT );
+        
+        SimpleNode n1 = new SimpleNode( "objectClass" , "1.2.3" , 0 );
+        SimpleNode n2 = new SimpleNode( "objectClass" , "4.5.6" , 0 );
+        SimpleNode n3 = new SimpleNode( "objectClass" , "person-7" , 0 );
+        BranchNode n4 = new BranchNode( AbstractExprNode.OR );
+        n4.addNode( n2 );
+        n4.addNode( n3 );
+        BranchNode n5 = new BranchNode( AbstractExprNode.AND );
+        n5.addNode( n1 );
+        n5.addNode( n4 );
+        SimpleNode n6 = new SimpleNode( "objectClass" , "10.11.12" , 0 );
+        BranchNode n7 = new BranchNode( AbstractExprNode.NOT );
+        n7.addNode( n6 );
+        BranchNode n8 = new BranchNode( AbstractExprNode.AND );
+        n8.addNode( n5 );
+        n8.addNode( n7 );
+        
+        assertEquals( n8 , ss.getRefinement() );
+    }
+    
+    
+    /**
+     * Tests the parser with a valid specification with base and empty refinement set.
+     */
+    public void testSpecWithBaseAndEmptyRefinement() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_BASE_AND_EMPTY_REFINEMENT );
+        
+        assertEquals( "ou=system" , ss.getBase().toString() );
+    }
+
+
+    /**
+     * Tests the parser with a valid specification with all components set.
+     */
+    public void testSpecWithAllInOne() throws Exception
+    {
+        SubtreeSpecification ss = parser.parse( SPEC_WITH_ALL_IN_ONE );
+        assertNotNull( ss );
+    }
+
+
+    /**
+     * Tests the parser with an invalid specification with wrong component order.
+     */
+    public void testInvalidSpecWithWrongComponentOrder() throws Exception
+    {    
+        try
+        {
+            SubtreeSpecification ss = parser.parse( INVALID_SPEC_WITH_WRONG_COMPONENT_ORDER
);
+            fail( "testInvalidSpecWithWrongComponentOrder() should never come here..." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+        catch ( IOException e )
+        {
+            assertNotNull( e );
+        }
+    }
+
+
+    /**
+     * Tests the parser with an invalid specification with silly things in.
+     */
+    public void testInvalidSillyThing() throws Exception
+    {    
+        try
+        {
+            SubtreeSpecification ss = parser.parse( INVALID_SILLY_THING );
+            fail( "testInvalidSillyThing() should never come here..." );
+        }
+        catch ( ParseException e )
+        {
+            assertNotNull( e );
+        }
+        catch ( IOException e )
+        {
+            assertNotNull( e );
+        }
+    }
+    
+    
+    /**
+     * Tests the multithreaded use of a single parser.
+     */
+    public void testMultiThreaded() throws Exception
+    {
+        // start up and track all threads (40 threads)
+        List threads = new ArrayList();
+        for ( int ii = 0; ii < 10; ii++ )
+        {
+            Thread t0 = new Thread( new ParseSpecification( EMPTY_SPEC ) );
+            Thread t1 = new Thread( new ParseSpecification( SPEC_WITH_SPECIFICEXCLUSIONS
) );
+            Thread t2 = new Thread( new ParseSpecification( SPEC_WITH_MINIMUM_AND_MAXIMUM
) );
+            Thread t3 = new Thread( new ParseSpecification( SPEC_WITH_ALL_IN_ONE ) );
+            threads.add( t0 );
+            threads.add( t1 );
+            threads.add( t2 );
+            threads.add( t3 );
+            t0.start();
+            t1.start();
+            t2.start();
+            t3.start();
+        }
+
+        // wait until all threads have died
+        boolean hasLiveThreads = false;
+        do
+        {
+            hasLiveThreads = false;
+
+            for ( int ii = 0; ii < threads.size(); ii ++ )
+            {
+                Thread t = ( Thread ) threads.get( ii );
+                hasLiveThreads = hasLiveThreads || t.isAlive();
+            }
+        }
+        while ( hasLiveThreads );
+
+        // check that no one thread failed to parse and generate a SS object
+        assertTrue( isSuccessMultithreaded );
+    }
+
+
+    /**
+     * Used to test multithreaded use of a single parser.
+     */
+    class ParseSpecification implements Runnable
+    {
+        private final String specStr;
+        SubtreeSpecification result;
+
+
+        public ParseSpecification( String specStr )
+        {
+            this.specStr = specStr;
+        }
+
+
+        public void run()
+        {
+            try
+            {
+                result = parser.parse( specStr );
+            }
+            catch ( ParseException e )
+            {
+                e.printStackTrace();
+            }
+            catch ( IOException e )
+            {
+                e.printStackTrace();
+            }
+
+            isSuccessMultithreaded = isSuccessMultithreaded && ( result != null );
+        }
+    }
+}

Added: directory/shared/ldap/trunk/common/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/trunk/common/src/test/resources/log4j.properties?rev=240354&view=auto
==============================================================================
--- directory/shared/ldap/trunk/common/src/test/resources/log4j.properties (added)
+++ directory/shared/ldap/trunk/common/src/test/resources/log4j.properties Fri Aug 26 15:10:09
2005
@@ -0,0 +1,5 @@
+log4j.rootCategory=INFO, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n

Modified: directory/shared/ldap/trunk/project.xml
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/trunk/project.xml?rev=240354&r1=240353&r2=240354&view=diff
==============================================================================
--- directory/shared/ldap/trunk/project.xml (original)
+++ directory/shared/ldap/trunk/project.xml Fri Aug 26 15:10:09 2005
@@ -62,6 +62,15 @@
     </license>
   </licenses>
 
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+        <artifactId>nlog4j</artifactId>
+        <version>1.2.14</version>
+        <url>http://slf4j.org/nlog4j</url>
+      </dependency>
+  </dependencies>
+
   <build>
     <nagEmailAddress>dev@directory.apache.org</nagEmailAddress>
     <sourceDirectory>${basedir}/src/java</sourceDirectory>
@@ -71,6 +80,14 @@
       <includes>
         <include>**/*Test.java</include>
       </includes>
+      <resources>
+        <resource>
+          <directory>${basedir}/src/test/resources</directory>
+          <includes>
+            <include>**/*</include>
+          </includes>
+        </resource>
+      </resources>
     </unitTest>
   </build>
 



Mime
View raw message