blob: 3681f45a305fa75342495ffd691ea99cffda363e [file] [log] [blame]
header
{
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.shared.ldap.model.subtree;
import java.util.Set;
import java.util.Map;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import org.apache.directory.shared.ldap.model.name.Dn;
import org.apache.directory.shared.ldap.model.filter.ExprNode;
import org.apache.directory.shared.ldap.model.filter.LeafNode;
import org.apache.directory.shared.ldap.model.filter.BranchNode;
import org.apache.directory.shared.ldap.model.filter.AndNode;
import org.apache.directory.shared.ldap.model.filter.OrNode;
import org.apache.directory.shared.ldap.model.filter.NotNode;
import org.apache.directory.shared.ldap.model.filter.EqualityNode;
import org.apache.directory.shared.ldap.model.filter.FilterParser;
import org.apache.directory.shared.ldap.model.schema.ObjectClass;
import org.apache.directory.shared.ldap.model.schema.SchemaManager;
import org.apache.directory.shared.ldap.model.subtree.SubtreeSpecification;
import org.apache.directory.shared.ldap.model.subtree.SubtreeSpecificationModifier;
import org.apache.directory.shared.ldap.model.schema.NormalizerMappingResolver;
import org.apache.directory.shared.ldap.model.schema.normalizers.OidNormalizer;
import org.apache.directory.shared.util.ComponentsMonitor;
import org.apache.directory.shared.util.OptionalComponentsMonitor;
import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
import org.apache.directory.shared.ldap.model.entry.StringValue;
import org.apache.directory.shared.ldap.model.exception.LdapException;
import org.apache.directory.shared.ldap.model.schema.MutableAttributeTypeImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
}
// ----------------------------------------------------------------------------
// parser class definition
// ----------------------------------------------------------------------------
/**
* The antlr generated subtree specification parser.
*
* @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
class AntlrSubtreeSpecificationParser extends Parser;
// ----------------------------------------------------------------------------
// parser options
// ----------------------------------------------------------------------------
options
{
k = 1;
defaultErrorHandler = false;
}
// ----------------------------------------------------------------------------
// parser initialization
// ----------------------------------------------------------------------------
{
private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationParser.class );
private NormalizerMappingResolver resolver;
private Set<Dn> chopBeforeExclusions = null;
private Set<Dn> chopAfterExclusions = null;
private SubtreeSpecificationModifier ssModifier = null;
/** The schemaManager */
private SchemaManager schemaManager;
/** The ObjectClass AT */
MutableAttributeTypeImpl OBJECT_CLASS_AT;
private ComponentsMonitor subtreeSpecificationComponentsMonitor = null;
/**
* Does nothing.
*/
public void init( SchemaManager schemaManager )
{
this.schemaManager = schemaManager;
OBJECT_CLASS_AT = schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT );
}
public void setNormalizerMappingResolver( NormalizerMappingResolver resolver )
{
this.resolver = resolver;
}
public boolean isNormalizing()
{
return this.resolver != null;
}
private int token2Integer( Token token ) throws RecognitionException
{
int i = 0;
try
{
i = Integer.parseInt( token.getText());
}
catch ( NumberFormatException e )
{
throw new RecognitionException( "Value of INTEGER token " +
token.getText() +
" cannot be converted to an Integer" );
}
return i;
}
}
// ----------------------------------------------------------------------------
// parser productions
// ----------------------------------------------------------------------------
wrapperEntryPoint 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, ssModifier, subtreeSpecificationComponentsMonitor,
// chopBeforeExclusions and chopAfterExclusions
// in case something is left from the last parse
ss = null;
ssModifier = new SubtreeSpecificationModifier();
subtreeSpecificationComponentsMonitor = new OptionalComponentsMonitor(
new String [] { "base", "specificExclusions", "minimum", "maximum", "specificationFilter" } );
chopBeforeExclusions = new HashSet<Dn>();
chopAfterExclusions = new HashSet<Dn>();
// always create a new filter parser in case we may have some statefulness problems with it
}
:
OPEN_CURLY ( SP )*
( subtreeSpecificationComponent ( SP )*
( SEP ( SP )* subtreeSpecificationComponent ( SP )* )* )?
CLOSE_CURLY
{
ss = ssModifier.getSubtreeSpecification();
}
;
subtreeSpecificationComponent
{
log.debug( "entered subtreeSpecification()" );
}
:
ss_base
{
subtreeSpecificationComponentsMonitor.useComponent( "base" );
}
| ss_specificExclusions
{
subtreeSpecificationComponentsMonitor.useComponent( "specificExclusions" );
}
| ss_minimum
{
subtreeSpecificationComponentsMonitor.useComponent( "minimum" );
}
| ss_maximum
{
subtreeSpecificationComponentsMonitor.useComponent( "maximum" );
}
| ss_specificationFilter
{
subtreeSpecificationComponentsMonitor.useComponent( "specificationFilter" );
}
;
exception
catch [IllegalArgumentException e]
{
throw new RecognitionException( e.getMessage() );
}
ss_base
{
log.debug( "entered ss_base()" );
Dn base = null;
}
:
ID_base ( SP )+ base=distinguishedName
{
ssModifier.setBase( base );
}
;
ss_specificExclusions
{
log.debug( "entered ss_specificExclusions()" );
}
:
ID_specificExclusions ( SP )+ specificExclusions
{
ssModifier.setChopBeforeExclusions( chopBeforeExclusions );
ssModifier.setChopAfterExclusions( chopAfterExclusions );
}
;
specificExclusions
{
log.debug( "entered specificExclusions()" );
}
:
OPEN_CURLY ( SP )*
( specificExclusion ( SP )*
( SEP ( SP )* specificExclusion ( SP )* )*
)?
CLOSE_CURLY
;
specificExclusion
{
log.debug( "entered specificExclusion()" );
}
:
chopBefore | chopAfter
;
chopBefore
{
log.debug( "entered chopBefore()" );
Dn chopBeforeExclusion = null;
}
:
ID_chopBefore ( SP )* COLON ( SP )* chopBeforeExclusion=distinguishedName
{
chopBeforeExclusions.add( chopBeforeExclusion );
}
;
chopAfter
{
log.debug( "entered chopAfter()" );
Dn chopAfterExclusion = null;
}
:
ID_chopAfter ( SP )* COLON ( SP )* chopAfterExclusion=distinguishedName
{
chopAfterExclusions.add( chopAfterExclusion );
}
;
ss_minimum
{
log.debug( "entered ss_minimum()" );
int minimum = 0;
}
:
ID_minimum ( SP )+ minimum=baseDistance
{
ssModifier.setMinBaseDistance( minimum );
}
;
ss_maximum
{
log.debug( "entered ss_maximum()" );
int maximum = 0;
}
:
ID_maximum ( SP )+ maximum=baseDistance
{
ssModifier.setMaxBaseDistance( maximum );
}
;
ss_specificationFilter
{
log.debug( "entered ss_specificationFilter()" );
ExprNode filterExpr = null;
}
:
ID_specificationFilter
( SP )+
(
( filterExpr=refinement )
|
( filterExpr=filter )
)
{ ssModifier.setRefinement( filterExpr ); }
;
filter returns [ ExprNode filterExpr = null ]
{
log.debug( "entered filter()" );
}
:
( filterToken:FILTER { filterExpr=FilterParser.parse( schemaManager, filterToken.getText() ); } )
;
exception
catch [Exception e]
{
throw new RecognitionException( "filterParser failed. " + e.getMessage() );
}
distinguishedName returns [ Dn name ]
{
log.debug( "entered distinguishedName()" );
name = null;
}
:
token:SAFEUTF8STRING
{
name = new Dn( token.getText() );
name.normalize( schemaManager );
log.debug( "recognized a DistinguishedName: " + token.getText() );
}
;
exception
catch [Exception e]
{
throw new RecognitionException( "dnParser failed for " + token.getText() + " " + e.getMessage() );
}
baseDistance returns [ int distance ]
{
log.debug( "entered baseDistance()" );
distance = 0;
}
:
token:INTEGER
{
distance = token2Integer( token );
}
;
oid returns [ String result ]
{
log.debug( "entered oid()" );
result = null;
Token token = null;
}
:
{ token = LT( 1 ); } // an interesting trick goes here ;-)
( DESCR | NUMERICOID )
{
result = token.getText();
log.debug( "recognized an oid: " + result );
}
;
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;
ObjectClass objectClass;
}
:
ID_item ( SP )* COLON ( SP )* oid=oid
{
try
{
objectClass = schemaManager.lookupObjectClassRegistry( oid );
}
catch ( LdapException le )
{
// The oid does not exist
// TODO : deal with such an exception
}
node = new EqualityNode( OBJECT_CLASS_AT, new StringValue( oid ) );
}
;
and returns [ BranchNode node ]
{
log.debug( "entered and()" );
node = null;
List<ExprNode> children = null;
}
:
ID_and ( SP )* COLON ( SP )* children=refinements
{
node = new AndNode( children );
}
;
or returns [ BranchNode node ]
{
log.debug( "entered or()" );
node = null;
List<ExprNode> children = null;
}
:
ID_or ( SP )* COLON ( SP )* children=refinements
{
node = new OrNode( children );
}
;
not returns [ BranchNode node ]
{
log.debug( "entered not()" );
node = null;
ExprNode child = null;
}
:
ID_not ( SP )* COLON ( SP )* child=refinement
{
node = new NotNode( child );
}
;
refinements returns [ List<ExprNode> children ]
{
log.debug( "entered refinements()" );
children = null;
ExprNode child = null;
List<ExprNode> tempChildren = new ArrayList<ExprNode>();
}
:
OPEN_CURLY ( SP )*
(
child=refinement ( SP )*
{
tempChildren.add( child );
}
( SEP ( SP )* child=refinement ( SP )*
{
tempChildren.add( child );
} )*
)? CLOSE_CURLY
{
children = tempChildren;
}
;
// ----------------------------------------------------------------------------
// lexer class definition
// ----------------------------------------------------------------------------
/**
* The parser's primary lexer.
*
* @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
class AntlrSubtreeSpecificationLexer extends Lexer;
// ----------------------------------------------------------------------------
// lexer options
// ----------------------------------------------------------------------------
options
{
k = 5;
charVocabulary = '\u0001'..'\u0127';
}
tokens
{
ID_base = "base";
ID_specificExclusions = "specificExclusions";
ID_chopBefore = "chopBefore";
ID_chopAfter = "chopAfter";
ID_minimum = "minimum";
ID_maximum = "maximum";
ID_specificationFilter = "specificationFilter";
ID_item = "item";
ID_and = "and";
ID_or = "or";
ID_not = "not";
}
//----------------------------------------------------------------------------
// lexer initialization
//----------------------------------------------------------------------------
{
private static final Logger log = LoggerFactory.getLogger( AntlrSubtreeSpecificationLexer.class );
}
// ----------------------------------------------------------------------------
// attribute description lexer rules from models
// ----------------------------------------------------------------------------
SP : ' ';
COLON : ':' { log.debug( "matched COLON(':')" ); } ;
OPEN_CURLY : '{' { log.debug( "matched LBRACKET('{')" ); } ;
CLOSE_CURLY : '}' { log.debug( "matched RBRACKET('}')" ); } ;
SEP : ',' { log.debug( "matched SEP(',')" ); } ;
SAFEUTF8STRING : '"'! ( SAFEUTF8CHAR )* '"'! { log.debug( "matched SAFEUTF8CHAR: \"" + getText() + "\"" ); } ;
DESCR : ALPHA ( ALPHA | DIGIT | '-' )* { log.debug( "matched DESCR" ); } ;
INTEGER_OR_NUMERICOID
:
( INTEGER DOT ) => NUMERICOID
{
$setType( NUMERICOID );
}
|
INTEGER
{
$setType( INTEGER );
}
;
protected INTEGER: DIGIT | ( LDIGIT ( DIGIT )+ ) { log.debug( "matched INTEGER: " + getText() ); } ;
protected NUMERICOID: INTEGER ( DOT INTEGER )+ { 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' ;
FILTER : '(' ( ( '&' (SP)* (FILTER)+ ) | ( '|' (SP)* (FILTER)+ ) | ( '!' (SP)* FILTER ) | FILTER_VALUE ) ')' (SP)* ;
protected FILTER_VALUE : (options{greedy=true;}: ~( ')' | '(' | '&' | '|' | '!' ) ( ~(')') )* ) ;