directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From akaras...@apache.org
Subject svn commit: rev 56793 - in incubator/directory/ldap/trunk/common: . src/antlr src/java/org/apache/ldap/common/filter src/test/org/apache/ldap/common/filter
Date Sun, 07 Nov 2004 00:14:55 GMT
Author: akarasulu
Date: Sat Nov  6 16:14:54 2004
New Revision: 56793

Added:
   incubator/directory/ldap/trunk/common/src/antlr/filter-lexer.g
   incubator/directory/ldap/trunk/common/src/antlr/filter-parser.g
   incubator/directory/ldap/trunk/common/src/antlr/filter-value-lexer.g
   incubator/directory/ldap/trunk/common/src/antlr/filter-value-parser.g
   incubator/directory/ldap/trunk/common/src/test/org/apache/ldap/common/filter/FilterParserImplTest.java
Removed:
   incubator/directory/ldap/trunk/common/src/antlr/filter.g
Modified:
   incubator/directory/ldap/trunk/common/maven.xml
   incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/filter/FilterParserImpl.java
Log:
Changes ...

This is the culmination of like 2 days of work to get the damn filter
parser working right according to RFC2254 and to the new LDAPBIS working
group drafts which will replace the LDAP RFC set.  Both documents are
accessible here:

http://www.faqs.org/rfcs/rfc2254.html
http://ietf.org/internet-drafts/draft-ietf-ldapbis-filter-08.txt

This new parser supports Unicode in the value encoding as required and is
fully functional.  Meaning it supports all the different extensible rule
forms and what not.

Alex



Modified: incubator/directory/ldap/trunk/common/maven.xml
==============================================================================
--- incubator/directory/ldap/trunk/common/maven.xml	(original)
+++ incubator/directory/ldap/trunk/common/maven.xml	Sat Nov  6 16:14:54 2004
@@ -41,7 +41,16 @@
 		<j:set var="maven.antlr.grammars" value="dnparser.g"/>
 		<attainGoal name="antlr:generate" />
 
-		<j:set var="maven.antlr.grammars" value="filter.g"/>
+		<j:set var="maven.antlr.grammars" value="filter-value-lexer.g"/>
+		<attainGoal name="antlr:generate" />
+
+		<j:set var="maven.antlr.grammars" value="filter-lexer.g"/>
+		<attainGoal name="antlr:generate" />
+
+		<j:set var="maven.antlr.grammars" value="filter-value-parser.g"/>
+		<attainGoal name="antlr:generate" />
+
+		<j:set var="maven.antlr.grammars" value="filter-parser.g"/>
 		<attainGoal name="antlr:generate" />
 
 		<delete file="./DnCommonTokenTypes.txt"/>
@@ -54,10 +63,6 @@
       toDir="target/classes/org/apache/ldap/common/name"
       />
     <copy
-      file="target/antlr/org/apache/ldap/common/filter/antlrFilterTokenTypes.txt"
-      toDir="target/classes/org/apache/ldap/common/filter"
-      />
-    <copy
       file="target/antlr/org/apache/ldap/common/name/antlrNameParserTokenTypes.txt"
       toDir="target/classes/org/apache/ldap/common/name"
       />
@@ -72,6 +77,22 @@
     <copy
       file="target/antlr/org/apache/ldap/common/name/antlrValueTokenTypes.txt"
       toDir="target/classes/org/apache/ldap/common/name"
+      />
+    <copy
+      file="target/antlr/org/apache/ldap/common/filter/AntlrFilterValueParserTokenTypes.txt"
+      toDir="target/classes/org/apache/ldap/common/filter"
+      />
+    <copy
+      file="target/antlr/org/apache/ldap/common/filter/FilterValueLexerTokenTypes.txt"
+      toDir="target/classes/org/apache/ldap/common/filter"
+      />
+    <copy
+      file="target/antlr/org/apache/ldap/common/filter/AntlrFilterParserTokenTypes.txt"
+      toDir="target/classes/org/apache/ldap/common/filter"
+      />
+    <copy
+      file="target/antlr/org/apache/ldap/common/filter/FilterLexerTokenTypes.txt"
+      toDir="target/classes/org/apache/ldap/common/filter"
       />
   </preGoal>
     

Added: incubator/directory/ldap/trunk/common/src/antlr/filter-lexer.g
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/antlr/filter-lexer.g	Sat Nov  6 16:14:54 2004
@@ -0,0 +1,127 @@
+// ----------------------------------------------------------------------------
+// file header
+// ----------------------------------------------------------------------------
+
+header {
+/*
+ *   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.filter;
+}
+
+// ----------------------------------------------------------------------------
+// class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * The filter parser's primary lexer.
+ * 
+ * @see <a href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-filter-08.txt">String
Representation of Search Filters</a>
+ * @see <a href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-models-12.txt">LDAP:
Directory Information Models</a>
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ */
+class AntlrFilterLexer extends Lexer;
+
+
+// ----------------------------------------------------------------------------
+// lexer options
+// ----------------------------------------------------------------------------
+
+options
+{
+	k=2;
+	charVocabulary='\u0001'..'\u0127';
+	exportVocab = FilterLexer;
+	importVocab = FilterValueLexer;
+}
+
+
+// ----------------------------------------------------------------------------
+// lexer class members
+// ----------------------------------------------------------------------------
+
+{
+    /** the selector key used by this class of lexer */
+    public static final String SELECTOR_KEY = "filterLexer";
+}
+
+
+// ----------------------------------------------------------------------------
+// attribute description lexer rules from models
+// ----------------------------------------------------------------------------
+
+
+WS  :   (   '#' (~'\n')* '\n' { newline(); }
+        |    ' '
+        |   '\t'
+        |   '\r' '\n' { newline(); }
+        |   '\n'      { newline(); }
+        |   '\r'      { newline(); }
+        )
+        {$setType(Token.SKIP);} //ignore this token
+    ;
+
+protected RANGLE: '>';
+
+protected LANGLE: '<';
+
+protected TILDE: '~';
+
+COLON: ':';
+
+ASTERISK: '*';
+
+EXCLAMATION: '!';
+
+EQUALS: '=';
+
+LPAREN: '(';
+
+RPAREN: ')';
+
+VERTBAR: '|';
+
+AMPERSTAND: '&';
+
+DN: ":dn";
+
+COLONEQUALS: ":=";
+
+APPROX: TILDE EQUALS;
+
+GREATEROREQUAL: RANGLE EQUALS;
+
+LESSOREQUAL: LANGLE EQUALS;
+
+protected DIGIT: '0' | LDIGIT;
+
+protected LDIGIT: '1'..'9';
+
+protected ALPHA: 'A'..'Z' | 'a'..'z';
+
+protected NUMBER: DIGIT | ( LDIGIT ( DIGIT )+ );
+
+protected NUMERICOID: NUMBER ( '.' NUMBER )+;
+
+protected DESCR: ALPHA ( ALPHA | DIGIT | '-' )*;
+
+protected OID: DESCR | NUMERICOID;
+
+protected OPTION: ( ALPHA | DIGIT | '-' )+;
+
+protected OPTIONS: ( ';' OPTION )*;
+
+ATTRIBUTEDESCRIPTION: OID OPTIONS;

Added: incubator/directory/ldap/trunk/common/src/antlr/filter-parser.g
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/antlr/filter-parser.g	Sat Nov  6 16:14:54 2004
@@ -0,0 +1,371 @@
+// ----------------------------------------------------------------------------
+// file header
+// ----------------------------------------------------------------------------
+
+header {
+/*
+ *   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.filter;
+
+
+import antlr.*;
+import java.util.ArrayList;
+}
+
+// ----------------------------------------------------------------------------
+// class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * An LDAP filter parser.
+ *
+ * @see <a href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-filter-08.txt">String
Representation of Search Filters</a>
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ */
+class AntlrFilterParser extends Parser;
+ 
+
+// ----------------------------------------------------------------------------
+// parser options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 5;
+	importVocab = FilterLexer;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser class members
+// ----------------------------------------------------------------------------
+
+{
+    /** the monitor used to track the activities of this parser */
+    FilterParserMonitor monitor;
+    /** the token stream selector used for multiplexing the underlying stream */
+    TokenStreamSelector selector;
+    /** the filter value encoding lexer */
+    AntlrFilterValueLexer valueLexer;
+    /** the value parser pulling tokens from the value lexer */
+    AntlrFilterValueParser valueParser;
+
+
+    /**
+     * Sets the token stream selector used for multiplexing the underlying stream.
+     *
+     * @param selector the token stream selector used for multiplexing
+     */
+    public void setSelector( TokenStreamSelector selector )
+    {
+        this.selector = selector;
+    }
+
+
+    /**
+     * Sets the filter value encoding lexer.
+     *
+     * @param valueLexer the filter value encoding lexer
+     */
+    public void setValueLexer( AntlrFilterValueLexer valueLexer )
+    {
+        this.valueLexer = valueLexer;
+    }
+
+
+    /**
+     * Sets the value parser pulling tokens from the value lexer.
+     *
+     * @param valueParser value parser pulling tokens from the value lexer
+     */
+    public void setValueParser( AntlrFilterValueParser valueParser )
+    {
+        this.valueParser = valueParser;
+    }
+
+
+    /**
+     * Sets the monitor used to track the activities of this parser.
+     *
+     * @param monitor used to track the activities of this parser
+     */
+    public void setFilterParserMonitor( FilterParserMonitor monitor )
+    {
+        this.monitor = monitor;
+    }
+
+
+    /**
+     * Monitors FilterParser events where it matches a production.
+     *
+     * @param production the name of the production matched
+     */
+    private void matchedProduction( String production )
+    {
+        if ( this.monitor != null )
+        {
+            this.monitor.matchedProduction( production );
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// ldap-filters lexer rules
+// ----------------------------------------------------------------------------
+
+
+/**
+ * The top level production for matching a filter expression.
+ */
+filter returns [ExprNode node]
+{
+    node = null;
+}
+    /*
+     * The right parenthesis is left off because it is consumed as a termination
+     * token for the VALUEENCODING token of the value lexer.  When non terminal
+     * nodes ( those other than filters with AND, OR and NOT'd expressions ) are
+     * encountered we match the right parenthesis in filtercomp().
+     */
+    : LPAREN node=filtercomp;
+
+
+/**
+ * A production for matching composite filter expressions.
+ */
+filtercomp returns [ExprNode node]
+{
+    node = null;
+}
+    /*
+     * Match the right parenthesis for any non-terminal production not directly
+     * using the value parser and value lexer to suck up values.
+     */
+    : node=and RPAREN | node=or RPAREN | node=not RPAREN | node=item;
+
+
+/**
+ * A recursive production for matching AND'd filter expressions.
+ */
+and returns [BranchNode node]
+{
+    node = null;
+    ExprNode child;
+    ArrayList children = new ArrayList();
+}
+    :
+    AMPERSTAND child=filter
+    {
+        children.add( child );
+    }
+    ( child=filter
+      {
+          children.add( child );
+      }
+    )+
+    {
+        node = new BranchNode( AbstractExprNode.AND, children );
+    }
+    ;
+
+
+/**
+ * A recursive production for matching OR'd filter expressions.
+ */
+or returns [BranchNode node]
+{
+    node = null;
+    ExprNode child;
+    ArrayList children = new ArrayList();
+}
+    :
+    VERTBAR child=filter
+    {
+        children.add( child );
+    }
+    ( child=filter
+      {
+          children.add( child );
+      }
+    )+
+    {
+        node = new BranchNode( AbstractExprNode.OR, children );
+    }
+    ;
+
+
+/**
+ * A recursive production for matching negated filter expressions.
+ */
+not returns [BranchNode node]
+{
+    node = null;
+    ExprNode child;
+}
+    : EXCLAMATION child=filter
+    {
+        node = new BranchNode( AbstractExprNode.NOT );
+        node.addNode( child );
+    }
+    ;
+
+
+/**
+ * A production for matching all non-terminal assertions.  This includes
+ * extensible, presence, substring, greaterorequal, lessorequal, and equality
+ * filter assertions.
+ */
+item returns [LeafNode node]
+{
+    node = null;
+}
+    : node=simple | node=extensible;
+
+
+/**
+ * General filter assertion matching production for approximate, greater or
+ * equal, less or equal, equals, substring, and presence simple items,
+ */
+simple returns [LeafNode node]
+{
+    String attribute = null;
+    node = null;
+    int type = -1;
+}
+    /*
+     * Reads the attribute description, the assertion operator, and then
+     * invokes the filter value parser.  Note that this rule switches the
+     * lexical state via the selector.  The invoked value parser automatically
+     * switches state back to the filter lexer.
+     */
+    : token:ATTRIBUTEDESCRIPTION
+    {
+        attribute = token.getText();
+    }
+    (
+      APPROX
+        {
+            type = AbstractExprNode.APPROXIMATE;
+        }
+    | GREATEROREQUAL
+        {
+            type = AbstractExprNode.GREATEREQ;
+        }
+    | LESSOREQUAL
+        {
+            type = AbstractExprNode.LESSEQ;
+        }
+    | EQUALS
+        {
+            type = AbstractExprNode.EQUALITY;
+        }
+    )
+      {
+        selector.select( valueLexer );
+        Object value = valueParser.value( attribute );
+
+        switch( type )
+        {
+            case( AbstractExprNode.APPROXIMATE ):
+            case( AbstractExprNode.GREATEREQ ):
+            case( AbstractExprNode.LESSEQ ):
+                node = new SimpleNode( attribute, ( String ) value, type );
+                break;
+            case( AbstractExprNode.EQUALITY ):
+                if ( value instanceof String )
+                {
+                    node = new SimpleNode( attribute, ( String ) value, type );
+                }
+                else
+                {
+                    node = ( LeafNode ) value;
+                }
+                break;
+            default:
+                throw new IllegalStateException( "Expecting one of 4 types" );
+        }
+      }
+    ;
+
+
+/**
+ * Extensible filter assertion matching production.
+ */
+extensible returns [ExtensibleNode node]
+{
+    node = null;
+    boolean dnAttrs = false;
+    String attribute = null;
+    String matchingRule = null;
+    String value = null;
+}
+    :
+    (
+        // A L T E R N A T I V E   1 :
+        attributeAlt1:ATTRIBUTEDESCRIPTION
+        {
+            attribute = attributeAlt1.getText();
+        }
+        ( DN { dnAttrs = true; } )?
+        ( COLON matchingRuleAlt1:ATTRIBUTEDESCRIPTION
+            {
+                matchingRule = matchingRuleAlt1.getText();
+                int idx = matchingRule.indexOf( ';' );
+                if ( idx != -1 )
+                {
+                    String msg = "matchingRule OIDs cannot have options: ";
+                    msg += matchingRule;
+                    throw new RecognitionException( msg, matchingRule, 0, idx );
+                }
+            }
+        )? COLONEQUALS
+        {
+            selector.select( valueLexer );
+            value = ( String ) valueParser.value( attribute );
+        }
+
+    |
+        // A L T E R N A T I V E   2 :
+        ( DN { dnAttrs = true; })? COLON matchingRuleAlt2:ATTRIBUTEDESCRIPTION
+            {
+                matchingRule = matchingRuleAlt2.getText();
+                int idx = matchingRule.indexOf( ';' );
+                if ( idx != -1 )
+                {
+                    String msg = "matchingRule OIDs cannot have options: ";
+                    msg += matchingRule;
+                    throw new RecognitionException( msg, matchingRule, 0, idx );
+                }
+            }
+        COLONEQUALS
+        {
+            selector.select( valueLexer );
+            value = ( String ) valueParser.value( attribute );
+        }
+    |
+        // A L T E R N A T I V E   3 :
+        COLONEQUALS
+        {
+            selector.select( valueLexer );
+            value = ( String ) valueParser.value( attribute );
+        }
+    )
+    {
+        node = new ExtensibleNode( attribute, value, matchingRule, dnAttrs );
+    }
+    ;
+

Added: incubator/directory/ldap/trunk/common/src/antlr/filter-value-lexer.g
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/antlr/filter-value-lexer.g	Sat Nov  6 16:14:54
2004
@@ -0,0 +1,154 @@
+// ----------------------------------------------------------------------------
+// file header
+// ----------------------------------------------------------------------------
+
+header {
+/*
+ *   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.filter;
+}
+
+// ----------------------------------------------------------------------------
+// class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * A lexer for LDAP search filter value encodings as defined by the ldapbis 
+ * draft describing the string representation of search filters.  This lexer is
+ * rather complex supporting the complete encoding with unicode support.  We 
+ * have separated it into its own lexer and intend to use it in a 
+ * TokenStreamSelector to multiplex lexical states in a parser.
+ * 
+ * @see <a href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-filter-08.txt">String
Representation of Search Filters</a>
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ */
+class AntlrFilterValueLexer extends Lexer;
+
+
+// ----------------------------------------------------------------------------
+// lexer options
+// ----------------------------------------------------------------------------
+
+options
+{
+	k=1;
+	
+	// allow any unicode characters
+	charVocabulary='\u0000'..'\uFFFE';
+	exportVocab=FilterValueLexer;
+}
+
+
+// ----------------------------------------------------------------------------
+// lexer class members
+// ----------------------------------------------------------------------------
+
+{
+    /** the selector key used by this class of lexer */
+    public static final String SELECTOR_KEY = "filterValueLexer";
+}
+
+
+// ----------------------------------------------------------------------------
+// abnf-core lexer rules used
+// ----------------------------------------------------------------------------
+
+protected DIGIT: '0'..'9';
+
+// A hexidecimal digit 
+protected HEXDIG: DIGIT | 'A'..'F' | 'a'..'f';
+
+
+// ----------------------------------------------------------------------------
+// filter lexer rules
+// ----------------------------------------------------------------------------
+
+// the value encoding in all its possible glory
+VALUEENCODING: ( NORMAL | ESCAPED )+;
+
+// anything besides escapes, 0x00 (NUL), LPAREN, RPAREN, ASTERISK, and ESC
+protected NORMAL: UTF1SUBSET | UTFMB;
+
+// escaped out hex representations of bytes 
+protected ESCAPED: ESC HEXDIG HEXDIG;
+
+// UTF1SUBSET excludes 0x00 (NUL), LPAREN, RPAREN, ASTERISK, and ESC
+// %x01-27 / %x2B-5B / %x5D-7F and we could defined it like so ==>
+// protected UTF1SUBSET: '\u0001'..'\u0039' | '\u0043'..'\u0091' | '\u0093'..'\u0127';
+// but we need to define it using an inverted caracter class to make 
+// VALUEENCODING work without nondeterminism.
+protected UTF1SUBSET: ~( '\\' | '\u0000' | '(' | ')' | '*' | '\u0128'..'\uFFFE' );
+
+// %x21 ; exclamation mark ("!")
+protected EXCLAMATION: '!';
+
+// %x26 ; ampersand (or AND symbol) ("&")
+protected AMPERSAND: "&" ;
+      
+// %x2A ; asterisk ("*")
+ASTERISK: '*';
+
+// %x28 ; left paren ("(")
+LPAREN: '(';
+
+// %x29 ; right paren (")")
+RPAREN: ')';
+
+// %x3A ; colon (":")
+protected COLON: ':';
+      
+// %x7C ; vertical bar (or pipe) ("|")      
+protected VERTBAR: '|';
+
+// tilde ~
+protected TILDE: '~';
+
+
+// ----------------------------------------------------------------------------
+// ldap-models lexer rules
+// ----------------------------------------------------------------------------
+
+protected ESC: '\\';
+
+// recognizes any UTF-8 encoded Unicode character
+protected UTF8: UTF1 | UTFMB;
+
+// the mulitbyte characters
+protected UTFMB: UTF2 | UTF3 | UTF4;
+
+// %x80-BF
+protected UTF0: '\u0128'..'\u0191';
+
+// %x00-7F      
+protected UTF1: '\u0000'..'\u0127';
+
+// %xC2-DF UTF0
+protected UTF2: '\u0194'..'\u0223' UTF0;
+
+// %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) / xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
+protected UTF3:   ( '\u0224' '\u0160'..'\u0191' UTF0 ) 
+				|          ( '\u0225'..'\u0236' UTF0 UTF0 ) 
+				| ( '\u0237' '\u0128'..'\u0159' UTF0 ) 
+				|          ( '\u0238'..'\u0239' UTF0 UTF0 );
+
+// %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) / %xF4 %x80-8F 2(UTF0)
+protected UTF4:   ( '\u0240' '\u0144'..'\u0191' UTF0 UTF0 ) 
+                |          ( '\u0241'..'\u0243' UTF0 UTF0 UTF0 ) 
+				| ( '\u0244' '\u0128'..'\u0143' UTF0 UTF0 );
+
+
+

Added: incubator/directory/ldap/trunk/common/src/antlr/filter-value-parser.g
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/antlr/filter-value-parser.g	Sat Nov  6 16:14:54
2004
@@ -0,0 +1,221 @@
+// ----------------------------------------------------------------------------
+// file header
+// ----------------------------------------------------------------------------
+
+header {
+/*
+ *   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.filter;
+
+
+import antlr.*;
+import java.util.*;
+}
+
+
+// ----------------------------------------------------------------------------
+// class definition
+// ----------------------------------------------------------------------------
+
+/**
+ * A filter assertion value encoding parser.  This parser is used by the top
+ * filter parser to handle equality, extensible, presence and substring
+ * assertion values.  It also participates in multiplexing the underlying
+ * token stream by driving filter assertion value lexer.
+ *
+ * @see <a href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-filter-08.txt">String
Representation of Search Filters</a>
+ * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
+ */
+class AntlrFilterValueParser extends Parser;
+ 
+
+// ----------------------------------------------------------------------------
+// parser options
+// ----------------------------------------------------------------------------
+
+options
+{
+    k = 3;
+	importVocab = FilterValueLexer;
+}
+
+
+// ----------------------------------------------------------------------------
+// parser class members
+// ----------------------------------------------------------------------------
+
+{
+    /** the monitor used to track the activities of this parser */
+    FilterParserMonitor monitor;
+    /** the primary lexer used by the filter parser */
+    AntlrFilterLexer lexer;
+    /** the token stream selector for the filter parser */
+    TokenStreamSelector selector;
+
+
+    /**
+     * Sets the token stream select so we can use it to switch to the filter
+     * parsers primary lexer.
+     *
+     * @param selector the token stream selector for the filter parser
+     */
+    public void setSelector( TokenStreamSelector selector )
+    {
+        this.selector = selector;
+    }
+
+
+    /**
+     * Sets the filter's main lexer so we can switch back to it.
+     *
+     * @param lexer the primary lexer used by the filter parser
+     */
+    public void setLexer( AntlrFilterLexer lexer )
+    {
+        this.lexer = lexer;
+    }
+
+
+    /**
+     * Sets the monitor used to track the activities of this parser.
+     *
+     * @param monitor used to track the activities of this parser
+     */
+    public void setFilterParserMonitor( FilterParserMonitor monitor )
+    {
+        this.monitor = monitor;
+    }
+
+
+    /**
+     * Monitors FilterParser events where it matches a production.
+     *
+     * @param production the name of the production matched
+     */
+    private void matchedProduction( String production )
+    {
+        if ( this.monitor != null )
+        {
+            this.monitor.matchedProduction( production );
+        }
+    }
+}
+
+
+
+// ----------------------------------------------------------------------------
+// parser rules
+// ----------------------------------------------------------------------------
+
+
+/**
+ * Parser production that calls either equal, presence or substring productions.
+ */
+value [String attribute] returns [Object node]
+{
+    node = null;
+}
+    : ( node=equal | node=presence[attribute] | node=substring[attribute] );
+
+
+/**
+ * Parser production that parses the equality expression value immediately
+ * after the '=' in a filter equality assertion.
+ */
+equal returns [String retval]
+{
+    retval = null;
+}
+    : val:VALUEENCODING
+    {
+        selector.select( lexer );
+        retval = val.getText();
+    }
+    RPAREN;
+
+
+/**
+ * Parser production that parses the presence expressions immediately after the
+ * '=' in a presence assertion.
+ */
+presence [String attribute] returns [PresenceNode node]
+{
+    node = null;
+}
+    : ASTERISK
+    {
+        selector.select( lexer );
+        node = new PresenceNode( attribute );
+    }
+    RPAREN;
+
+
+/**
+ * Parser production that parses the substring expression value immediately
+ * after the '=' in a substring filter assertion.
+ */
+substring [String attribute] returns [SubstringNode node]
+{
+    node = null;
+    String initial = null;
+    String fin = null;
+    ArrayList any = new ArrayList();
+}
+    :
+    (
+        // A L T E R N A T I V E   1:    initial*
+        alt1:VALUEENCODING
+        {
+            initial = alt1.getText();
+        }
+        ASTERISK
+    |
+        // A L T E R N A T I V E   2:    (*any) *final
+        ( ASTERISK alt2:VALUEENCODING
+        {
+            if ( fin != null )
+            {
+                any.add( fin );
+            }
+
+            fin = alt2.getText();
+        }
+        )+
+    |
+        // A L T E R N A T I V E   3:    initial (*any) *final
+        alt3t0:VALUEENCODING
+        {
+            initial = alt3t0.getText();
+        }
+        ( ASTERISK alt3t1:VALUEENCODING
+        {
+            if ( fin != null )
+            {
+                any.add( fin );
+            }
+
+            fin = alt3t1.getText();
+        }
+        )+
+    )
+    RPAREN
+    {
+        selector.select( lexer );
+        node = new SubstringNode( any, attribute, initial, fin );
+    }
+    ;
+

Modified: incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/filter/FilterParserImpl.java
==============================================================================
--- incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/filter/FilterParserImpl.java
(original)
+++ incubator/directory/ldap/trunk/common/src/java/org/apache/ldap/common/filter/FilterParserImpl.java
Sat Nov  6 16:14:54 2004
@@ -14,121 +14,122 @@
  *   limitations under the License.
  *
  */
-package org.apache.ldap.common.filter ;
+package org.apache.ldap.common.filter;
 
 
-import java.io.IOException ;
-import java.text.ParseException ;
-import java.io.PipedInputStream ;
-import java.io.PipedOutputStream ;
-
-import org.apache.ldap.common.util.ExceptionUtils;
-import antlr.RecognitionException ;
-import antlr.TokenStreamException ;
-
-
-/**
- * A FilterParser implementation based on antlr.
- * 
- * @author <a href="mailto:aok123@bellsouth.net">Alex Karasulu</a>
- * @author $Author: akarasulu $
- * @version $Revision: 1.7 $
- */
-public class FilterParserImpl
-    implements FilterParser
+import java.io.PipedOutputStream;
+import java.io.PipedInputStream;
+import java.io.IOException;
+import java.text.ParseException;
+
+import antlr.*;
+
+
+public class FilterParserImpl implements FilterParser
 {
-    private FilterParserMonitor monitor = new FilterParserMonitorAdapter() ;
-    /** The antlr generated parser */
-    private antlrFilterParser m_parser = null ;
-    /** A pipe into the parser */
-    private PipedOutputStream m_parserIn = null ;
-    
+    private AntlrFilterParser parser;
+    private PipedOutputStream parserPipe;
+    private AntlrFilterLexer lexer;
+    private TokenStreamSelector selector;
+    private LexerSharedInputState state;
+    private AntlrFilterValueLexer valueLexer;
+    private AntlrFilterValueParser valueParser;
+
 
     /**
-     * Creates an instance of FilterParserImpl. 
-     *
-     * @throws IOException if the pipe cannot be formed 
+     * Creates a filter parser implementation.
      */
     public FilterParserImpl()
-        throws IOException
     {
-        init() ;
+        init();
     }
 
 
     /**
-     * Initializes a parser and its plumbing.
-     *
-     * @throws IOException if a pipe cannot be formed.
+     * Initializes the filter parser.
      */
-    public void init()
-        throws IOException
+    private synchronized void init()
     {
-        m_parserIn = new PipedOutputStream() ;
-        PipedInputStream l_in = new PipedInputStream() ;
-        m_parserIn.connect( l_in ) ;
-        antlrFilterLexer l_lexer = new antlrFilterLexer( l_in ) ;
-        m_parser = new antlrFilterParser( l_lexer ) ;
-       
+        // build the pipe used to feed the parser data and reusing it
+        this.parserPipe = new PipedOutputStream();
+        PipedInputStream pipeTail = new PipedInputStream();
+
+        try
+        {
+            this.parserPipe.connect( pipeTail );
+        }
+        catch ( IOException e )
+        {
+            // this never blows chuncks and if it does we report!
+            e.printStackTrace();
+        }
+
+        this.state = new LexerSharedInputState( pipeTail );
+        this.lexer = new AntlrFilterLexer( state );
+        this.valueLexer = new AntlrFilterValueLexer( state );
+
+        this.selector = new TokenStreamSelector();
+        this.selector.addInputStream( this.lexer, AntlrFilterLexer.SELECTOR_KEY );
+        this.selector.addInputStream( this.valueLexer, AntlrFilterValueLexer.SELECTOR_KEY
);
+        this.selector.select( this.lexer );
+
+        this.parser = new AntlrFilterParser( this.selector );
+        this.parser.setSelector( this.selector );
+        this.parser.setValueLexer( this.valueLexer );
+        this.parser.setValueParser( this.valueParser );
+
+        this.valueParser = new AntlrFilterValueParser( this.selector );
+        this.valueParser.setSelector( this.selector );
+        this.valueParser.setLexer( this.lexer );
+
+        this.parser.setValueParser( this.valueParser );
     }
 
 
-    /**
-     * Thread safe method parses a_filter.
-     *
-     * @see org.apache.ldap.common.filter.FilterParser#parse(java.lang.String)
-     */
-    public synchronized ExprNode parse( String a_filter )
-        throws IOException, ParseException
+    public synchronized ExprNode parse( String filter ) throws ParseException, IOException
     {
-        ExprNode l_root = null ;
+        ExprNode root = null;
 
-        if ( a_filter == null || a_filter.trim().equals( "" ) ) 
+        if ( filter == null || filter.trim().equals( "" ) )
         {
             throw new ParseException( "The filter string is either null or is "
                 + "the empty String!", 0 ) ;
         }
 
-        if ( null == monitor )
-        {
-            monitor = new FilterParserMonitorAdapter() ;
-        }
-
-        m_parserIn.write( a_filter.getBytes() ) ;
-        m_parserIn.write( '\n' ) ;
-        m_parserIn.flush() ;
+        this.parserPipe.write( filter.getBytes() ) ;
+        this.parserPipe.write( '\n' ) ;
+        this.parserPipe.flush() ;
 
-        try 
+        try
         {
-            l_root = m_parser.filter() ;
-        } 
-        catch ( RecognitionException e ) 
+            root = this.parser.filter() ;
+            this.state.reset();
+            this.selector.select( this.lexer );
+        }
+        catch ( RecognitionException e )
         {
-            String l_msg = "Parser failure on filter:\n\t" + a_filter ;
-            l_msg += "\nAntlr exception trace:\n" 
-                + ExceptionUtils.getFullStackTrace( e ) ;
+            // @todo either use ExceptionUtils here or switch to throwing a
+            // naming exception instead.
+            String msg = "Parser failure on filter:\n\t" + filter ;
+            msg += "\nAntlr exception trace:\n" + e.getMessage() ;
             init() ;
-            throw new ParseException( l_msg, e.getColumn() ) ;
-        } 
-        catch ( TokenStreamException e2 ) 
-        {
-            String l_msg = "Parser failure on filter:\n\t" + a_filter ;
-            l_msg += "\nAntlr exception trace:\n" 
-                + ExceptionUtils.getFullStackTrace( e2 ) ;
+            throw new ParseException( msg, e.getColumn() ) ;
+        }
+        catch ( TokenStreamException e2 )
+        {
+            String msg = "Parser failure on filter:\n\t" + filter ;
+            msg += "\nAntlr exception trace:\n" + e2.getMessage();
             init() ;
-            throw new ParseException( l_msg, 0 ) ;
+            throw new ParseException( msg, 0 ) ;
         }
 
-        return l_root ;
+        return root;
     }
-    
-    
-    /* (non-Javadoc)
-     * @see org.apache.ldap.common.filter.FilterParser#setFilterParserMonitor(
-     * org.apache.ldap.common.filter.FilterParserMonitor)
-     */
+
+
     public void setFilterParserMonitor( FilterParserMonitor monitor )
     {
-        this.monitor = monitor ;
+        this.parser.setFilterParserMonitor( monitor );
+        this.valueParser.setFilterParserMonitor( monitor );
     }
 }

Added: incubator/directory/ldap/trunk/common/src/test/org/apache/ldap/common/filter/FilterParserImplTest.java
==============================================================================
--- (empty file)
+++ incubator/directory/ldap/trunk/common/src/test/org/apache/ldap/common/filter/FilterParserImplTest.java
Sat Nov  6 16:14:54 2004
@@ -0,0 +1,279 @@
+/*
+ *   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.filter;
+
+
+import java.io.IOException;
+import java.text.ParseException;
+
+import junit.framework.TestCase;
+
+
+/**
+ * Tests the FilterParserImpl class.
+ *
+ * @author <a href="mailto:directory-dev@incubator.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class FilterParserImplTest extends TestCase
+{
+    private FilterParserImpl parser;
+
+
+    protected void setUp() throws Exception
+    {
+        parser = new FilterParserImpl();
+    }
+
+
+    protected void tearDown() throws Exception
+    {
+        parser = null;
+    }
+
+
+    public void testItemFilter() throws IOException, ParseException
+    {
+        parser.parse( "( ou ~= people )" );
+    }
+
+
+    public void testAndFilter() throws IOException, ParseException
+    {
+        parser.parse( "(& ( ou ~= people ) (age>=30) ) " );
+    }
+
+
+    public void testOrFilter() throws IOException, ParseException
+    {
+        parser.parse( "(| ( ou ~= people ) (age>=30) ) " );
+    }
+
+
+    public void testNotFilter() throws IOException, ParseException
+    {
+        parser.parse( "( ! (& ( ou ~= people ) (age>=30) ) )" );
+    }
+
+
+    public void testOptionAndEscapesFilter() throws IOException, ParseException
+    {
+        parser.parse( "( ou;lang-de >= \\23\\42asdl fkajsd )" );
+    }
+
+
+    public void testOptionsAndEscapesFilter() throws IOException, ParseException
+    {
+        parser.parse( "( ou;lang-de;version-124 >= \\23\\42asdl fkajsd )" );
+    }
+
+
+    public void testNumericoidOptionsAndEscapesFilter() throws IOException, ParseException
+    {
+        parser.parse( "( 1.3.4.2;lang-de;version-124 >= \\23\\42asdl fkajsd )" );
+    }
+
+
+    public void testPresentFilter() throws IOException, ParseException
+    {
+        parser.parse( "( ou =* )" );
+    }
+
+
+    public void testNumericoidPresentFilter() throws IOException, ParseException
+    {
+        parser.parse( "( 1.2.3.4 = * )" );
+    }
+
+
+    public void testEqualsFilter() throws IOException, ParseException
+    {
+        parser.parse( "( ou = people )" );
+    }
+
+
+    public void testEqualsWithForwardSlashFilter() throws IOException, ParseException
+    {
+        parser.parse( "( ou = people/in/my/company )" );
+    }
+
+
+    public void testExtensibleFilterForm1() throws IOException, ParseException
+    {
+        parser.parse( "( ou :dn :stupidMatch := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testExtensibleFilterForm1WithNumericOid() throws IOException, ParseException
+    {
+        parser.parse( "( 1.2.3.4 :dn :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testExtensibleFilterForm1NoDnAttr() throws IOException, ParseException
+    {
+        parser.parse( "( ou :stupidMatch := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testExtensibleFilterForm1OptionOnRule() throws IOException, ParseException
+    {
+        try
+        {
+            parser.parse( "( ou :stupidMatch;lang-de := dummyAssertion\\23\\ac )" );
+            fail( "we should never get here" );
+        }
+        catch ( IOException e )
+        {
+        }
+        catch ( ParseException e )
+        {
+        }
+    }
+
+
+    public void testExtensibleFilterForm1NoAttrNoMatchingRule() throws IOException, ParseException
+    {
+        parser.parse( "( ou := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testExtensibleFilterForm1NoDnAttrWithNumericOidNoAttr() throws IOException,
ParseException
+    {
+        parser.parse( "( 1.2.3.4 :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testExtensibleFilterForm2() throws IOException, ParseException
+    {
+        parser.parse( "( :dn :stupidMatch := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testExtensibleFilterForm2OptionOnRule() throws IOException, ParseException
+    {
+        try
+        {
+            parser.parse( "( :dn :stupidMatch;lang-en := dummyAssertion\\23\\ac )" );
+            fail( "we should never get here" );
+        }
+        catch ( IOException e )
+        {
+        }
+        catch ( ParseException e )
+        {
+        }
+    }
+
+
+    public void testExtensibleFilterForm2WithNumericOid() throws IOException, ParseException
+    {
+        parser.parse( "( :dn :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testExtensibleFilterForm2NoDnAttr() throws IOException, ParseException
+    {
+        parser.parse( "( :stupidMatch := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testExtensibleFilterForm2NoDnAttrWithNumericOidNoAttr() throws IOException,
ParseException
+    {
+        parser.parse( "( :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testExtensibleFilterForm3() throws IOException, ParseException
+    {
+        parser.parse( "( := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testReuseParser() throws IOException, ParseException
+    {
+        parser.parse( "( ou ~= people )" );
+        parser.parse( "(& ( ou ~= people ) (age>=30) ) " );
+        parser.parse( "(| ( ou ~= people ) (age>=30) ) " );
+        parser.parse( "( ! (& ( ou ~= people ) (age>=30) ) )" );
+        parser.parse( "( ou;lang-de >= \\23\\42asdl fkajsd )" );
+        parser.parse( "( ou;lang-de;version-124 >= \\23\\42asdl fkajsd )" );
+        parser.parse( "( 1.3.4.2;lang-de;version-124 >= \\23\\42asdl fkajsd )" );
+        parser.parse( "( ou =* )" );
+        parser.parse( "( 1.2.3.4 = * )" );
+        parser.parse( "( ou = people )" );
+        parser.parse( "( ou = people/in/my/company )" );
+        parser.parse( "( ou :dn :stupidMatch := dummyAssertion\\23\\ac )" );
+        parser.parse( "( 1.2.3.4 :dn :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+        parser.parse( "( ou :stupidMatch := dummyAssertion\\23\\ac )" );
+        parser.parse( "( ou := dummyAssertion\\23\\ac )" );
+        parser.parse( "( 1.2.3.4 :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+        parser.parse( "( :dn :stupidMatch := dummyAssertion\\23\\ac )" );
+        parser.parse( "( :dn :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+        parser.parse( "( :stupidMatch := dummyAssertion\\23\\ac )" );
+        parser.parse( "( :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+        parser.parse( "( := dummyAssertion\\23\\ac )" );
+    }
+
+
+    public void testReuseParserAfterFailures() throws IOException, ParseException
+    {
+        parser.parse( "( ou ~= people )" );
+        parser.parse( "(& ( ou ~= people ) (age>=30) ) " );
+        parser.parse( "(| ( ou ~= people ) (age>=30) ) " );
+        parser.parse( "( ! (& ( ou ~= people ) (age>=30) ) )" );
+        parser.parse( "( ou;lang-de >= \\23\\42asdl fkajsd )" );
+        parser.parse( "( ou;lang-de;version-124 >= \\23\\42asdl fkajsd )" );
+        parser.parse( "( 1.3.4.2;lang-de;version-124 >= \\23\\42asdl fkajsd )" );
+        try
+        {
+            parser.parse( "( ou :stupidMatch;lang-de := dummyAssertion\\23\\ac )" );
+            fail( "we should never get here" );
+        }
+        catch ( IOException e )
+        {
+        }
+        catch ( ParseException e )
+        {
+        }
+        parser.parse( "( ou =* )" );
+        parser.parse( "( 1.2.3.4 = * )" );
+        parser.parse( "( ou = people )" );
+        parser.parse( "( ou = people/in/my/company )" );
+        parser.parse( "( ou :dn :stupidMatch := dummyAssertion\\23\\ac )" );
+        parser.parse( "( 1.2.3.4 :dn :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+        parser.parse( "( ou :stupidMatch := dummyAssertion\\23\\ac )" );
+        try
+        {
+            parser.parse( "( :dn :stupidMatch;lang-en := dummyAssertion\\23\\ac )" );
+            fail( "we should never get here" );
+        }
+        catch ( IOException e )
+        {
+        }
+        catch ( ParseException e )
+        {
+        }
+        parser.parse( "( ou := dummyAssertion\\23\\ac )" );
+        parser.parse( "( 1.2.3.4 :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+        parser.parse( "( :dn :stupidMatch := dummyAssertion\\23\\ac )" );
+        parser.parse( "( :dn :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+        parser.parse( "( :stupidMatch := dummyAssertion\\23\\ac )" );
+        parser.parse( "( :1.3434.23.2 := dummyAssertion\\23\\ac )" );
+        parser.parse( "( := dummyAssertion\\23\\ac )" );
+    }
+}

Mime
View raw message