header
{
/*
* Copyright 2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.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.DnParser;
import org.apache.ldap.common.name.NameComponentNormalizer;
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;
}
// ----------------------------------------------------------------------------
// parser class definition
// ----------------------------------------------------------------------------
/**
* The antlr generated subtree specification parser.
*
* @see RFC 3672
* @author Apache Directory Project
* @version $Rev$
*/
class AntlrSubtreeSpecificationParser extends Parser;
// ----------------------------------------------------------------------------
// parser options
// ----------------------------------------------------------------------------
options
{
k = 2;
defaultErrorHandler = false;
}
// ----------------------------------------------------------------------------
// parser initialization
// ----------------------------------------------------------------------------
{
private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationParser.class );
private DnParser dnParser;
private boolean isNormalizing = false;
NameComponentNormalizer normalizer;
private Set chopBeforeExclusions = new HashSet();
private Set chopAfterExclusions = new HashSet();
SubtreeSpecificationModifier ssModifier = null;
/**
* Creates a (normalizing) subordinate DnParser for parsing LocalNames.
* This method MUST be called for each instance while we cannot do
* constructor overloading for this class.
*
* @return the DnParser to be used for parsing LocalNames
*/
public void init()
{
try
{
if( isNormalizing )
{
dnParser = new DnParser( normalizer );
}
else
{
dnParser = new DnParser();
}
}
catch ( NamingException e )
{
String msg = "Failed to initialize the subordinate DnParser for this AntlrSubtreeSpecificationParser";
// 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 );
}
}
/**
* Sets the NameComponentNormalizer for this parser's dnParser.
*/
public void setNormalizer(NameComponentNormalizer normalizer)
{
this.normalizer = normalizer;
this.isNormalizing = true;
}
}
// ----------------------------------------------------------------------------
// 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 ss_base_follower
| ss_specificExclusions ss_specificExclusions_follower
| ss_minimum ss_minimum_follower
| ss_maximum ss_maximum_follower
| ss_specificationFilter
)
( SP )*
)?
RBRACKET
{
ss = ssModifier.getSubtreeSpecification();
}
;
ss_base_follower
:
( SEP ( SP )*
(
ss_specificExclusions ss_specificExclusions_follower
| ss_minimum ss_minimum_follower
| ss_maximum ss_maximum_follower
| ss_specificationFilter
)
)?
;
ss_specificExclusions_follower
:
( SEP ( SP )*
(
ss_minimum ss_minimum_follower
| ss_maximum ss_maximum_follower
| ss_specificationFilter
)
)?
;
ss_minimum_follower
:
( SEP ( SP )*
(
ss_maximum ss_maximum_follower
| ss_specificationFilter
)
)?
;
ss_maximum_follower
:
( SEP ( SP )*
(
ss_specificationFilter
)
)?
;
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
( SP
child=refinement
{
tempChildren.add( child );
}
( SEP ( SP )* child=refinement
{
tempChildren.add( child );
} )*
)? ( SP )* RBRACKET
{
children = tempChildren;
}
;
// ----------------------------------------------------------------------------
// lexer class definition
// ----------------------------------------------------------------------------
/**
* The parser's primary lexer.
*
* @see RFC 3672
* @author Apache Directory Project
* @version $Rev$
*/
class AntlrSubtreeSpecificationLexer extends Lexer;
// ----------------------------------------------------------------------------
// lexer options
// ----------------------------------------------------------------------------
options
{
k = 2;
charVocabulary = '\u0001'..'\u0127';
testLiterals = false;
}
//----------------------------------------------------------------------------
// lexer initialization
//----------------------------------------------------------------------------
{
private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationLexer.class );
}
// ----------------------------------------------------------------------------
// attribute description lexer rules from models
// ----------------------------------------------------------------------------
SP : ' ';
COLON : ':' { log.debug( "matched COLON(':')" ); } ;
LBRACKET : '{' { log.debug( "matched LBRACKET('{')" ); } ;
RBRACKET : '}' { log.debug( "matched RBRACKET('}')" ); } ;
DQUOTE : '"' { log.debug( "matched DQUOTE('\"')" ); } ;
SEP : ',' { log.debug( "matched SEP(',')" ); } ;
DQUOTEDSTRING : DQUOTE! ( SAFEUTF8CHAR )* DQUOTE! { log.debug( "matched DQUOTEDSTRING: \"" + getText() + "\"" ); } ;
DESCR options { testLiterals = true; } : ALPHA ( ALPHA | DIGIT | '-' )* { log.debug( "matched DESCR" ); } ;
// This rule is required to prevent nondeterminism problem caused by NUMBER and NUMERICOID rules.
NUMBER_OR_NUMERICOID
:
( NUMBER DOT ) => NUMERICOID
{
$setType(NUMERICOID);
}
|
NUMBER
{
$setType(NUMBER);
}
;
protected NUMBER: DIGIT | ( LDIGIT ( DIGIT )+ ) { log.debug( "matched NUMBER: " + getText() ); } ;
protected NUMERICOID: NUMBER ( DOT NUMBER )+ { log.debug( "matched NUMERICOID: " + getText() ); } ;
protected DOT: '.' ;
protected DIGIT: '0' | LDIGIT ;
protected LDIGIT: '1'..'9' ;
protected ALPHA: 'A'..'Z' | 'a'..'z' ;
// This is all messed up - could not figure out how to get antlr to represent
// the safe UTF-8 character set from RFC 3642 for production SafeUTF8Character
protected SAFEUTF8CHAR:
'\u0001'..'\u0021' |
'\u0023'..'\u007F' |
'\u00c0'..'\u00d6' |
'\u00d8'..'\u00f6' |
'\u00f8'..'\u00ff' |
'\u0100'..'\u1fff' |
'\u3040'..'\u318f' |
'\u3300'..'\u337f' |
'\u3400'..'\u3d2d' |
'\u4e00'..'\u9fff' |
'\uf900'..'\ufaff' ;