blob: fca526ca5c43bbe45e0bf539c1e11c85171d8cce [file] [log] [blame]
/*
* 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.api.ldap.model.filter;
import java.text.ParseException;
import org.apache.directory.api.i18n.I18n;
import org.apache.directory.api.ldap.model.entry.AttributeUtils;
import org.apache.directory.api.ldap.model.entry.BinaryValue;
import org.apache.directory.api.ldap.model.entry.StringValue;
import org.apache.directory.api.ldap.model.entry.Value;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.schema.AttributeType;
import org.apache.directory.api.ldap.model.schema.SchemaManager;
import org.apache.directory.api.util.Chars;
import org.apache.directory.api.util.Hex;
import org.apache.directory.api.util.Position;
import org.apache.directory.api.util.Strings;
import org.apache.directory.api.util.Unicode;
/**
* This class parse a Ldap filter. The grammar is given in RFC 4515
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public final class FilterParser
{
private FilterParser()
{
}
/**
* Parse an extensible
*
* extensible = ( attr [":dn"] [':' oid] ":=" assertionvalue )
* / ( [":dn"] ':' oid ":=" assertionvalue )
* matchingrule = ":" oid
*/
private static ExprNode parseExtensible( SchemaManager schemaManager, String attribute, byte[] filter,
Position pos, boolean relaxed ) throws LdapException, ParseException
{
ExtensibleNode node = null;
if ( schemaManager != null )
{
AttributeType attributeType = schemaManager.getAttributeType( attribute );
if ( attributeType != null )
{
node = new ExtensibleNode( attributeType );
}
else
{
return UndefinedNode.UNDEFINED_NODE;
}
}
else
{
node = new ExtensibleNode( attribute );
}
if ( attribute != null )
{
// First check if we have a ":dn"
if ( Strings.areEquals( filter, pos.start, "dn" ) >= 0 )
{
// Set the dnAttributes flag and move forward in the string
node.setDnAttributes( true );
pos.start += 2;
}
else
{
// Push back the ':'
pos.start--;
}
// Do we have a MatchingRule ?
if ( Strings.byteAt( filter, pos.start ) == ':' )
{
pos.start++;
if ( Strings.byteAt( filter, pos.start ) == '=' )
{
pos.start++;
// Get the assertionValue
node.setValue( parseAssertionValue( schemaManager, filter, pos ) );
return node;
}
else
{
String matchingRuleId = AttributeUtils.parseAttribute( filter, pos, false, relaxed );
node.setMatchingRuleId( matchingRuleId );
if ( Strings.areEquals( filter, pos.start, ":=" ) >= 0 )
{
pos.start += 2;
// Get the assertionValue
node.setValue( parseAssertionValue( schemaManager, filter, pos ) );
return node;
}
else
{
throw new ParseException( I18n.err( I18n.ERR_04146 ), pos.start );
}
}
}
else
{
throw new ParseException( I18n.err( I18n.ERR_04147 ), pos.start );
}
}
else
{
// No attribute
boolean oidRequested = false;
// First check if we have a ":dn"
if ( Strings.areEquals( filter, pos.start, ":dn" ) >= 0 )
{
// Set the dnAttributes flag and move forward in the string
node.setDnAttributes( true );
pos.start += 3;
}
else
{
oidRequested = true;
}
// Do we have a MatchingRule ?
if ( Strings.byteAt( filter, pos.start ) == ':' )
{
pos.start++;
if ( Strings.byteAt( filter, pos.start ) == '=' )
{
if ( oidRequested )
{
throw new ParseException( I18n.err( I18n.ERR_04148 ), pos.start );
}
pos.start++;
// Get the assertionValue
node.setValue( parseAssertionValue( schemaManager, null, filter, pos ) );
return node;
}
else
{
String matchingRuleId = AttributeUtils.parseAttribute( filter, pos, false, relaxed );
node.setMatchingRuleId( matchingRuleId );
if ( Strings.areEquals( filter, pos.start, ":=" ) >= 0 )
{
pos.start += 2;
// Get the assertionValue
node.setValue( parseAssertionValue( schemaManager, null, filter, pos ) );
return node;
}
else
{
throw new ParseException( I18n.err( I18n.ERR_04146 ), pos.start );
}
}
}
else
{
throw new ParseException( I18n.err( I18n.ERR_04147 ), pos.start );
}
}
}
/**
* An assertion value :
* assertionvalue = valueencoding
* valueencoding = 0*(normal / escaped)
* normal = UTF1SUBSET / UTFMB
* escaped = '\' HEX HEX
* HEX = '0'-'9' / 'A'-'F' / 'a'-'f'
* UTF1SUBSET = %x01-27 / %x2B-5B / %x5D-7F (Everything but '\0', '*', '(', ')' and '\')
* UTFMB = UTF2 / UTF3 / UTF4
* UTF0 = %x80-BF
* UTF2 = %xC2-DF UTF0
* UTF3 = %xE0 %xA0-BF UTF0 / %xE1-EC UTF0 UTF0 / %xED %x80-9F UTF0 / %xEE-EF UTF0 UTF0
* UTF4 = %xF0 %x90-BF UTF0 UTF0 / %xF1-F3 UTF0 UTF0 UTF0 / %xF4 %x80-8F UTF0 UTF0
*
* With the specific constraints (RFC 4515):
* "The <valueencoding> rule ensures that the entire filter string is a"
* "valid UTF-8 string and provides that the octets that represent the"
* "ASCII characters "*" (ASCII 0x2a), "(" (ASCII 0x28), ")" (ASCII"
* "0x29), "\" (ASCII 0x5c), and NUL (ASCII 0x00) are represented as a"
* "backslash "\" (ASCII 0x5c) followed by the two hexadecimal digits"
* "representing the value of the encoded octet."
*
* The incoming String is already transformed from UTF-8 to unicode, so we must assume that the
* grammar we have to check is the following :
*
* assertionvalue = valueencoding
* valueencoding = 0*(normal / escaped)
* normal = unicodeSubset
* escaped = '\' HEX HEX
* HEX = '0'-'9' / 'A'-'F' / 'a'-'f'
* unicodeSubset = %x01-27 / %x2B-5B / %x5D-FFFF
* @throws LdapInvalidAttributeValueException
*/
private static Value<?> parseAssertionValue( SchemaManager schemaManager, String attribute, byte[] filter,
Position pos ) throws ParseException
{
byte b = Strings.byteAt( filter, pos.start );
// Create a buffer big enough to contain the value once converted
byte[] value = new byte[filter.length - pos.start];
int current = 0;
do
{
if ( Unicode.isUnicodeSubset( b ) )
{
value[current++] = b;
pos.start++;
}
else if ( Strings.isCharASCII( filter, pos.start, '\\' ) )
{
// Maybe an escaped
pos.start++;
// First hex
if ( Chars.isHex( filter, pos.start ) )
{
pos.start++;
}
else
{
throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
}
// second hex
if ( Chars.isHex( filter, pos.start ) )
{
value[current++] = Hex.getHexValue( filter[pos.start - 1], filter[pos.start] );
pos.start++;
}
else
{
throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
}
}
else
{
// not a valid char, so let's get out
break;
}
b = Strings.byteAt( filter, pos.start );
}
while ( b != '\0' );
if ( current != 0 )
{
byte[] result = new byte[current];
System.arraycopy( value, 0, result, 0, current );
if ( schemaManager != null )
{
AttributeType attributeType = schemaManager.getAttributeType( attribute );
if ( attributeType == null )
{
return new BinaryValue( result );
}
if ( attributeType.getSyntax().isHumanReadable() )
{
return new StringValue( Strings.utf8ToString( result ) );
}
else
{
return new BinaryValue( result );
}
}
else
{
return new BinaryValue( result );
}
}
else
{
if ( schemaManager != null )
{
AttributeType attributeType = schemaManager.getAttributeType( attribute );
if ( attributeType.getEquality().getSyntax().isHumanReadable() )
{
return new StringValue( ( String ) null );
}
else
{
return new BinaryValue( null );
}
}
else
{
return new BinaryValue( ( byte[] ) null );
}
}
}
/**
* An assertion value :
* assertionvalue = valueencoding
* valueencoding = 0*(normal / escaped)
* normal = UTF1SUBSET / UTFMB
* escaped = '\' HEX HEX
* HEX = '0'-'9' / 'A'-'F' / 'a'-'f'
* UTF1SUBSET = %x01-27 / %x2B-5B / %x5D-7F (Everything but '\0', '*', '(', ')' and '\')
* UTFMB = UTF2 / UTF3 / UTF4
* UTF0 = %x80-BF
* UTF2 = %xC2-DF UTF0
* UTF3 = %xE0 %xA0-BF UTF0 / %xE1-EC UTF0 UTF0 / %xED %x80-9F UTF0 / %xEE-EF UTF0 UTF0
* UTF4 = %xF0 %x90-BF UTF0 UTF0 / %xF1-F3 UTF0 UTF0 UTF0 / %xF4 %x80-8F UTF0 UTF0
*
* With the specific constraints (RFC 4515):
* "The <valueencoding> rule ensures that the entire filter string is a"
* "valid UTF-8 string and provides that the octets that represent the"
* "ASCII characters "*" (ASCII 0x2a), "(" (ASCII 0x28), ")" (ASCII"
* "0x29), "\" (ASCII 0x5c), and NUL (ASCII 0x00) are represented as a"
* "backslash "\" (ASCII 0x5c) followed by the two hexadecimal digits"
* "representing the value of the encoded octet."
*
* The incoming String is already transformed from UTF-8 to unicode, so we must assume that the
* grammar we have to check is the following :
*
* assertionvalue = valueencoding
* valueencoding = 0*(normal / escaped)
* normal = unicodeSubset
* escaped = '\' HEX HEX
* HEX = '0'-'9' / 'A'-'F' / 'a'-'f'
* unicodeSubset = %x01-27 / %x2B-5B / %x5D-FFFF
*/
private static Value<?> parseAssertionValue( SchemaManager schemaManager, byte[] filter, Position pos )
throws ParseException
{
byte b = Strings.byteAt( filter, pos.start );
// Create a buffer big enough to contain the value once converted
byte[] value = new byte[filter.length - pos.start];
int current = 0;
do
{
if ( Unicode.isUnicodeSubset( b ) )
{
value[current++] = b;
pos.start++;
}
else if ( Strings.isCharASCII( filter, pos.start, '\\' ) )
{
// Maybe an escaped
pos.start++;
// First hex
if ( Chars.isHex( filter, pos.start ) )
{
pos.start++;
}
else
{
throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
}
// second hex
if ( Chars.isHex( filter, pos.start ) )
{
value[current++] = Hex.getHexValue( filter[pos.start - 1], filter[pos.start] );
pos.start++;
}
else
{
throw new ParseException( I18n.err( I18n.ERR_04149 ), pos.start );
}
}
else
{
// not a valid char, so let's get out
break;
}
b = Strings.byteAt( filter, pos.start );
}
while ( b != '\0' );
if ( current != 0 )
{
byte[] result = new byte[current];
System.arraycopy( value, 0, result, 0, current );
return new BinaryValue( result );
}
else
{
return new BinaryValue( null );
}
}
/**
* Parse a substring
*/
private static ExprNode parseSubstring( SchemaManager schemaManager, String attribute, Value<?> initial,
byte[] filter, Position pos )
throws ParseException, LdapException
{
if ( Strings.isCharASCII( filter, pos.start, '*' ) )
{
// We have found a '*' : this is a substring
SubstringNode node = null;
if ( schemaManager != null )
{
AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( attribute );
if ( attributeType != null )
{
node = new SubstringNode( schemaManager.lookupAttributeTypeRegistry( attribute ) );
}
else
{
return null;
}
}
else
{
node = new SubstringNode( attribute );
}
if ( ( initial != null ) && !initial.isNull() )
{
// We have a substring starting with a value : val*...
// Set the initial value. It must be a String
String initialStr = initial.getString();
node.setInitial( initialStr );
}
pos.start++;
//
while ( true )
{
Value<?> assertionValue = parseAssertionValue( schemaManager, attribute, filter, pos );
// Is there anything else but a ')' after the value ?
if ( Strings.isCharASCII( filter, pos.start, ')' ) )
{
// Nope : as we have had [initial] '*' (any '*' ) *,
// this is the final
if ( !assertionValue.isNull() )
{
String finalStr = assertionValue.getString();
node.setFinal( finalStr );
}
return node;
}
else if ( Strings.isCharASCII( filter, pos.start, '*' ) )
{
// We have a '*' : it's an any
// If the value is empty, that means we have more than
// one consecutive '*' : do nothing in this case.
if ( !assertionValue.isNull() )
{
String anyStr = assertionValue.getString();
node.addAny( anyStr );
}
pos.start++;
}
else
{
// This is an error
throw new ParseException( I18n.err( I18n.ERR_04150 ), pos.start );
}
}
}
else
{
// This is an error
throw new ParseException( I18n.err( I18n.ERR_04150 ), pos.start );
}
}
/**
* Here is the grammar to parse :
*
* simple ::= '=' assertionValue
* present ::= '=' '*'
* substring ::= '=' [initial] any [final]
* initial ::= assertionValue
* any ::= '*' ( assertionValue '*')*
*
* As we can see, there is an ambiguity in the grammar : attr=* can be
* seen as a present or as a substring. As stated in the RFC :
*
* "Note that although both the <substring> and <present> productions in"
* "the grammar above can produce the "attr=*" construct, this construct"
* "is used only to denote a presence filter." (RFC 4515, 3)
*
* We have also to consider the difference between a substring and the
* equality node : this last node does not contain a '*'
*
* @param attributeType
* @param filter
* @param pos
* @return
*/
@SuppressWarnings(
{ "rawtypes", "unchecked" })
private static ExprNode parsePresenceEqOrSubstring( SchemaManager schemaManager, String attribute, byte[] filter,
Position pos )
throws ParseException, LdapException
{
if ( Strings.isCharASCII( filter, pos.start, '*' ) )
{
// To be a present node, the next char should be a ')'
pos.start++;
if ( Strings.isCharASCII( filter, pos.start, ')' ) )
{
// This is a present node
if ( schemaManager != null )
{
AttributeType attributeType = schemaManager.getAttributeType( attribute );
if ( attributeType != null )
{
return new PresenceNode( attributeType );
}
else
{
return null;
}
}
else
{
return new PresenceNode( attribute );
}
}
else
{
// Definitively a substring with no initial or an error
// Push back the '*' on the string
pos.start--;
return parseSubstring( schemaManager, attribute, null, filter, pos );
}
}
else if ( Strings.isCharASCII( filter, pos.start, ')' ) )
{
// An empty equality Node
if ( schemaManager != null )
{
AttributeType attributeType = schemaManager.getAttributeType( attribute );
if ( attributeType != null )
{
return new EqualityNode( attributeType, new BinaryValue( ( byte[] ) null ) );
}
else
{
return null;
}
}
else
{
return new EqualityNode( attribute, new BinaryValue( ( byte[] ) null ) );
}
}
else
{
// A substring or an equality node
Value<?> value = parseAssertionValue( schemaManager, attribute, filter, pos );
// Is there anything else but a ')' after the value ?
if ( Strings.isCharASCII( filter, pos.start, ')' ) )
{
// This is an equality node
if ( schemaManager != null )
{
AttributeType attributeType = schemaManager.getAttributeType( attribute );
if ( attributeType != null )
{
return new EqualityNode( attributeType, value );
}
else
{
return null;
}
}
else
{
return new EqualityNode( attribute, value );
}
}
return parseSubstring( schemaManager, attribute, value, filter, pos );
}
}
/**
* Parse the following grammar :
* item = simple / present / substring / extensible
* simple = attr filtertype assertionvalue
* filtertype = '=' / '~=' / '>=' / '<='
* present = attr '=' '*'
* substring = attr '=' [initial] any [final]
* extensible = ( attr [":dn"] [':' oid] ":=" assertionvalue )
* / ( [":dn"] ':' oid ":=" assertionvalue )
* matchingrule = ":" oid
*
* An item starts with an attribute or a colon.
*/
@SuppressWarnings(
{ "rawtypes", "unchecked" })
private static ExprNode parseItem( SchemaManager schemaManager, byte[] filter, Position pos, byte b,
boolean relaxed ) throws ParseException, LdapException
{
String attribute = null;
if ( b == '\0' )
{
throw new ParseException( I18n.err( I18n.ERR_04151 ), pos.start );
}
if ( b == ':' )
{
// If we have a colon, then the item is an extensible one
return parseExtensible( schemaManager, null, filter, pos, relaxed );
}
else
{
// We must have an attribute
attribute = AttributeUtils.parseAttribute( filter, pos, true, relaxed );
// Now, we may have a present, substring, simple or an extensible
b = Strings.byteAt( filter, pos.start );
switch ( b )
{
case '=':
// It can be a presence, an equal or a substring
pos.start++;
return parsePresenceEqOrSubstring( schemaManager, attribute, filter, pos );
case '~':
// Approximate node
pos.start++;
// Check that we have a '='
if ( !Strings.isCharASCII( filter, pos.start, '=' ) )
{
throw new ParseException( I18n.err( I18n.ERR_04152 ), pos.start );
}
pos.start++;
// Parse the value and create the node
if ( schemaManager == null )
{
return new ApproximateNode( attribute, parseAssertionValue( schemaManager, attribute, filter,
pos ) );
}
else
{
AttributeType attributeType = schemaManager.getAttributeType( attribute );
if ( attributeType != null )
{
return new ApproximateNode( attributeType, parseAssertionValue( schemaManager, attribute,
filter, pos ) );
}
else
{
return UndefinedNode.UNDEFINED_NODE;
}
}
case '>':
// Greater or equal node
pos.start++;
// Check that we have a '='
if ( !Strings.isCharASCII( filter, pos.start, '=' ) )
{
throw new ParseException( I18n.err( I18n.ERR_04152 ), pos.start );
}
pos.start++;
// Parse the value and create the node
if ( schemaManager == null )
{
return new GreaterEqNode( attribute,
parseAssertionValue( schemaManager, attribute, filter, pos ) );
}
else
{
AttributeType attributeType = schemaManager.getAttributeType( attribute );
if ( attributeType != null )
{
return new GreaterEqNode( attributeType, parseAssertionValue( schemaManager, attribute,
filter, pos ) );
}
else
{
return UndefinedNode.UNDEFINED_NODE;
}
}
case '<':
// Less or equal node
pos.start++;
// Check that we have a '='
if ( !Strings.isCharASCII( filter, pos.start, '=' ) )
{
throw new ParseException( I18n.err( I18n.ERR_04152 ), pos.start );
}
pos.start++;
// Parse the value and create the node
if ( schemaManager == null )
{
return new LessEqNode( attribute, parseAssertionValue( schemaManager, attribute, filter, pos ) );
}
else
{
AttributeType attributeType = schemaManager.getAttributeType( attribute );
if ( attributeType != null )
{
return new LessEqNode( attributeType, parseAssertionValue( schemaManager, attribute,
filter, pos ) );
}
else
{
return UndefinedNode.UNDEFINED_NODE;
}
}
case ':':
// An extensible node
pos.start++;
return parseExtensible( schemaManager, attribute, filter, pos, relaxed );
default:
// This is an error
throw new ParseException( I18n.err( I18n.ERR_04153 ), pos.start );
}
}
}
/**
* Parse AND, OR and NOT nodes :
*
* and = '&' filterlist
* or = '|' filterlist
* not = '!' filter
* filterlist = 1*filter
*
* @return
*/
private static ExprNode parseBranchNode( SchemaManager schemaManager, ExprNode node, byte[] filter, Position pos,
boolean relaxed ) throws ParseException, LdapException
{
BranchNode branchNode = ( BranchNode ) node;
int nbChildren = 0;
// We must have at least one filter
ExprNode child = parseFilterInternal( schemaManager, filter, pos, relaxed );
if ( child != UndefinedNode.UNDEFINED_NODE )
{
// Add the child to the node children
branchNode.addNode( child );
if ( branchNode instanceof NotNode )
{
return node;
}
nbChildren++;
}
else if ( node instanceof AndNode )
{
return UndefinedNode.UNDEFINED_NODE;
}
// Now, iterate recusively though all the remaining filters, if any
while ( ( child = parseFilterInternal( schemaManager, filter, pos, relaxed ) ) != UndefinedNode.UNDEFINED_NODE )
{
// Add the child to the node children if not null
if ( child != null )
{
branchNode.addNode( child );
nbChildren++;
}
else if ( node instanceof AndNode )
{
return UndefinedNode.UNDEFINED_NODE;
}
}
if ( nbChildren > 0 )
{
return node;
}
else
{
return UndefinedNode.UNDEFINED_NODE;
}
}
/**
* filtercomp = and / or / not / item
* and = '&' filterlist
* or = '|' filterlist
* not = '!' filter
* item = simple / present / substring / extensible
* simple = attr filtertype assertionvalue
* present = attr EQUALS ASTERISK
* substring = attr EQUALS [initial] any [final]
* extensible = ( attr [dnattrs]
* [matchingrule] COLON EQUALS assertionvalue )
* / ( [dnattrs]
* matchingrule COLON EQUALS assertionvalue )
*/
private static ExprNode parseFilterComp( SchemaManager schemaManager, byte[] filter, Position pos,
boolean relaxed ) throws ParseException, LdapException
{
ExprNode node = null;
if ( pos.start == pos.length )
{
throw new ParseException( I18n.err( I18n.ERR_04154 ), pos.start );
}
byte c = Strings.byteAt( filter, pos.start );
switch ( c )
{
case '&':
// This is a AND node
pos.start++;
node = new AndNode();
node = parseBranchNode( schemaManager, node, filter, pos, relaxed );
break;
case '|':
// This is an OR node
pos.start++;
node = new OrNode();
node = parseBranchNode( schemaManager, node, filter, pos, relaxed );
break;
case '!':
// This is a NOT node
pos.start++;
node = new NotNode();
node = parseBranchNode( schemaManager, node, filter, pos, relaxed );
break;
default:
// This is an item
node = parseItem( schemaManager, filter, pos, c, relaxed );
break;
}
return node;
}
/**
* Pasre the grammar rule :
* filter ::= '(' filterComp ')'
*/
private static ExprNode parseFilterInternal( SchemaManager schemaManager, byte[] filter, Position pos,
boolean relaxed ) throws ParseException, LdapException
{
// Check for the left '('
if ( !Strings.isCharASCII( filter, pos.start, '(' ) )
{
// No more node, get out
if ( ( pos.start == 0 ) && ( pos.length != 0 ) )
{
throw new ParseException( I18n.err( I18n.ERR_04155 ), 0 );
}
else
{
return UndefinedNode.UNDEFINED_NODE;
}
}
pos.start++;
// parse the filter component
ExprNode node = parseFilterComp( schemaManager, filter, pos, relaxed );
if ( node == UndefinedNode.UNDEFINED_NODE )
{
return UndefinedNode.UNDEFINED_NODE;
}
// Check that we have a right ')'
if ( !Strings.isCharASCII( filter, pos.start, ')' ) )
{
throw new ParseException( I18n.err( I18n.ERR_04157 ), pos.start );
}
pos.start++;
return node;
}
/**
* Parses a search filter from it's string representation to an expression node object.
*
* @param filter the search filter in it's string representation
* @return the expression node object
*/
public static ExprNode parse( String filter ) throws ParseException
{
return parse( null, Strings.getBytesUtf8( filter ), false );
}
/**
* @see FilterParser#parse(String)
*/
public static ExprNode parse( byte[] filter ) throws ParseException
{
return parse( null, filter, false );
}
/**
* @see FilterParser#parse(String)
*/
public static ExprNode parse( SchemaManager schemaManager, String filter ) throws ParseException
{
return parse( schemaManager, Strings.getBytesUtf8( filter ), false );
}
/**
* @see FilterParser#parse(String)
*/
public static ExprNode parse( SchemaManager schemaManager, byte[] filter ) throws ParseException
{
return parse( schemaManager, filter, false );
}
private static ExprNode parse( SchemaManager schemaManager, byte[] filter, boolean relaxed )
throws ParseException
{
// The filter must not be null. This is a defensive test
if ( Strings.isEmpty( filter ) )
{
throw new ParseException( I18n.err( I18n.ERR_04158 ), 0 );
}
Position pos = new Position();
pos.start = 0;
pos.end = 0;
pos.length = filter.length;
try
{
return parseFilterInternal( schemaManager, filter, pos, relaxed );
}
catch ( LdapException le )
{
throw new ParseException( le.getMessage(), pos.start );
}
}
/**
* @see FilterParser#parse(String)
*/
public static ExprNode parse( SchemaManager schemaManager, String filter, Position pos ) throws ParseException
{
// The filter must not be null. This is a defensive test
if ( Strings.isEmpty( filter ) )
{
throw new ParseException( I18n.err( I18n.ERR_04158 ), 0 );
}
pos.start = 0;
pos.end = 0;
pos.length = filter.length();
try
{
return parseFilterInternal( schemaManager, Strings.getBytesUtf8( filter ), pos, false );
}
catch ( LdapException le )
{
throw new ParseException( le.getMessage(), pos.start );
}
}
/**
* Parses a search filter from it's string representation to an expression node object.
*
* In <code>relaxed</code> mode the filter may violate RFC 4515, e.g. the underscore in attribute names is allowed.
*
* @param filter the search filter in it's string representation
* @param relaxed <code>true</code> to parse the filter in relaxed mode
* @return the expression node object
*/
public static ExprNode parse( String filter, boolean relaxed ) throws ParseException
{
return parse( null, Strings.getBytesUtf8( filter ), relaxed );
}
}