|
|
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@xxxxxxxxxxxxx">Alex Karasulu</a>
+ * @author <a href="mailto:dev@xxxxxxxxxxxxxxxxxxxx">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@xxxxxxxxxxxxx">Alex Karasulu</a>
+ * @author <a href="mailto:dev@xxxxxxxxxxxxxxxxxxxx">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@xxxxxxxxxxxxxxxxxxxx">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@xxxxxxxxxxxxxxxxxxxx">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@xxxxxxxxxxxxxxxxxxxx">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@xxxxxxxxxxxxxxxxxxxx">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@xxxxxxxxxxxxxxxxxxxx</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>
|
|