/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2013-2014 Manuel Gaupp
* Portions Copyright 2014-2015 ForgeRock AS
*/
package org.opends.server.controls;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.io.ASN1Reader;
import org.forgerock.opendj.io.ASN1Writer;
import org.forgerock.opendj.ldap.Assertion;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.schema.MatchingRule;
import org.forgerock.util.Reject;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.types.AttributeType;
import org.opends.server.types.LDAPException;
import org.opends.server.types.RawFilter;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.server.protocols.ldap.LDAPConstants.*;
import static org.opends.server.util.StaticUtils.*;
/**
* This class defines a filter that may be used in conjunction with the matched
* values control to indicate which particular values of a multivalued attribute
* should be returned. The matched values filter is essentially a subset of an
* LDAP search filter, lacking support for AND, OR, and NOT components, and
* lacking support for the dnAttributes component of extensible matching
* filters.
*/
public class MatchedValuesFilter
{
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
/** The BER type associated with the equalityMatch filter type. */
public static final byte EQUALITY_MATCH_TYPE = (byte) 0xA3;
/** The BER type associated with the substrings filter type. */
public static final byte SUBSTRINGS_TYPE = (byte) 0xA4;
/** The BER type associated with the greaterOrEqual filter type. */
public static final byte GREATER_OR_EQUAL_TYPE = (byte) 0xA5;
/** The BER type associated with the lessOrEqual filter type. */
public static final byte LESS_OR_EQUAL_TYPE = (byte) 0xA6;
/** The BER type associated with the present filter type. */
public static final byte PRESENT_TYPE = (byte) 0x87;
/** The BER type associated with the approxMatch filter type. */
public static final byte APPROXIMATE_MATCH_TYPE = (byte) 0xA8;
/** The BER type associated with the extensibleMatch filter type. */
public static final byte EXTENSIBLE_MATCH_TYPE = (byte) 0xA9;
/** The matching rule ID for this matched values filter. */
private final String matchingRuleID;
/** Indicates whether the elements of this matched values filter have been fully decoded. */
private boolean decoded;
/** The match type for this matched values filter. */
private final byte matchType;
/** The raw, unprocessed attribute type for this matched values filter. */
private final String rawAttributeType;
/** The processed attribute type for this matched values filter. */
private AttributeType attributeType;
/** The matching rule for this matched values filter. */
private MatchingRule matchingRule;
/** The equality matching rule for this matched values filter. */
private MatchingRule equalityMatchingRule;
/** The ordering matching rule for this matched values filter. */
private MatchingRule orderingMatchingRule;
/** The substring matching rule for this matched values filter. */
private MatchingRule substringMatchingRule;
/** The approximate matching rule for this matched values filter. */
private MatchingRule approximateMatchingRule;
/** The raw, unprocessed assertion value for this matched values filter. */
private final ByteString rawAssertionValue;
/** The processed assertion value for this matched values filter. */
private ByteString assertionValue;
/** The assertion created from substring matching rule using values of this filter. */
private Assertion substringAssertion;
/** The subInitial value for this matched values filter. */
private final ByteString subInitial;
/** The set of subAny values for this matched values filter. */
private final List<ByteString> subAny;
/** The subFinal value for this matched values filter. */
private final ByteString subFinal;
/**
* Creates a new matched values filter with the provided information.
*
* @param matchType The match type for this matched values filter.
* @param rawAttributeType The raw, unprocessed attribute type.
* @param rawAssertionValue The raw, unprocessed assertion value.
* @param subInitial The subInitial element.
* @param subAny The set of subAny elements.
* @param subFinal The subFinal element.
* @param matchingRuleID The matching rule ID.
*/
private MatchedValuesFilter(byte matchType, String rawAttributeType,
ByteString rawAssertionValue,
ByteString subInitial, List<ByteString> subAny,
ByteString subFinal, String matchingRuleID)
{
this.matchType = matchType;
this.rawAttributeType = rawAttributeType;
this.rawAssertionValue = rawAssertionValue;
this.subInitial = subInitial;
this.subAny = subAny;
this.subFinal = subFinal;
this.matchingRuleID = matchingRuleID;
}
/**
* Creates a new equalityMatch filter with the provided information.
*
* @param rawAttributeType The raw, unprocessed attribute type.
* @param rawAssertionValue The raw, unprocessed assertion value.
*
* @return The created equalityMatch filter.
*/
public static MatchedValuesFilter createEqualityFilter(
String rawAttributeType,
ByteString rawAssertionValue)
{
Reject.ifNull(rawAttributeType,rawAssertionValue);
return new MatchedValuesFilter(EQUALITY_MATCH_TYPE, rawAttributeType,
rawAssertionValue, null, null, null, null);
}
/**
* Creates a new equalityMatch filter with the provided information.
*
* @param attributeType The attribute type.
* @param assertionValue The assertion value.
*
* @return The created equalityMatch filter.
*/
public static MatchedValuesFilter createEqualityFilter(
AttributeType attributeType,
ByteString assertionValue)
{
Reject.ifNull(attributeType, assertionValue);
String rawAttributeType = attributeType.getNameOrOID();
MatchedValuesFilter filter =
new MatchedValuesFilter(EQUALITY_MATCH_TYPE, rawAttributeType,
assertionValue, null, null, null, null);
filter.attributeType = attributeType;
filter.assertionValue = assertionValue;
return filter;
}
/**
* Creates a new substrings filter with the provided information.
*
* @param rawAttributeType The raw, unprocessed attribute type.
* @param subInitial The subInitial element.
* @param subAny The set of subAny elements.
* @param subFinal The subFinal element.
*
* @return The created substrings filter.
*/
public static MatchedValuesFilter createSubstringsFilter(
String rawAttributeType,
ByteString subInitial,
List<ByteString> subAny,
ByteString subFinal)
{
Reject.ifNull(rawAttributeType);
return new MatchedValuesFilter(SUBSTRINGS_TYPE, rawAttributeType, null,
subInitial, subAny, subFinal, null);
}
/**
* Creates a new substrings filter with the provided information.
*
* @param attributeType The raw, unprocessed attribute type.
* @param subInitial The subInitial element.
* @param subAny The set of subAny elements.
* @param subFinal The subFinal element.
*
* @return The created substrings filter.
*/
public static MatchedValuesFilter createSubstringsFilter(
AttributeType attributeType,
ByteString subInitial,
List<ByteString> subAny,
ByteString subFinal)
{
Reject.ifNull(attributeType);
String rawAttributeType = attributeType.getNameOrOID();
MatchedValuesFilter filter =
new MatchedValuesFilter(SUBSTRINGS_TYPE, rawAttributeType, null,
subInitial, subAny, subFinal, null);
filter.attributeType = attributeType;
return filter;
}
/**
* Creates a new greaterOrEqual filter with the provided information.
*
* @param rawAttributeType The raw, unprocessed attribute type.
* @param rawAssertionValue The raw, unprocessed assertion value.
*
* @return The created greaterOrEqual filter.
*/
public static MatchedValuesFilter createGreaterOrEqualFilter(
String rawAttributeType,
ByteString rawAssertionValue)
{
Reject.ifNull(rawAttributeType, rawAssertionValue);
return new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE, rawAttributeType,
rawAssertionValue, null, null, null, null);
}
/**
* Creates a new greaterOrEqual filter with the provided information.
*
* @param attributeType The attribute type.
* @param assertionValue The assertion value.
*
* @return The created greaterOrEqual filter.
*/
public static MatchedValuesFilter createGreaterOrEqualFilter(
AttributeType attributeType,
ByteString assertionValue)
{
Reject.ifNull(attributeType, assertionValue);
String rawAttributeType = attributeType.getNameOrOID();
MatchedValuesFilter filter =
new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE, rawAttributeType,
assertionValue, null, null, null, null);
filter.attributeType = attributeType;
filter.assertionValue = assertionValue;
return filter;
}
/**
* Creates a new lessOrEqual filter with the provided information.
*
* @param rawAttributeType The raw, unprocessed attribute type.
* @param rawAssertionValue The raw, unprocessed assertion value.
*
* @return The created lessOrEqual filter.
*/
public static MatchedValuesFilter createLessOrEqualFilter(
String rawAttributeType,
ByteString rawAssertionValue)
{
Reject.ifNull(rawAttributeType, rawAssertionValue);
return new MatchedValuesFilter(LESS_OR_EQUAL_TYPE, rawAttributeType,
rawAssertionValue, null, null, null, null);
}
/**
* Creates a new lessOrEqual filter with the provided information.
*
* @param attributeType The attribute type.
* @param assertionValue The assertion value.
*
* @return The created lessOrEqual filter.
*/
public static MatchedValuesFilter createLessOrEqualFilter(
AttributeType attributeType,
ByteString assertionValue)
{
Reject.ifNull(attributeType, assertionValue);
String rawAttributeType = attributeType.getNameOrOID();
MatchedValuesFilter filter =
new MatchedValuesFilter(LESS_OR_EQUAL_TYPE, rawAttributeType,
assertionValue, null, null, null, null);
filter.attributeType = attributeType;
filter.assertionValue = assertionValue;
return filter;
}
/**
* Creates a new present filter with the provided information.
*
* @param rawAttributeType The raw, unprocessed attribute type.
*
* @return The created present filter.
*/
public static MatchedValuesFilter createPresentFilter(String rawAttributeType)
{
Reject.ifNull(rawAttributeType) ;
return new MatchedValuesFilter(PRESENT_TYPE, rawAttributeType, null, null,
null, null, null);
}
/**
* Creates a new present filter with the provided information.
*
* @param attributeType The attribute type.
*
* @return The created present filter.
*/
public static MatchedValuesFilter createPresentFilter(
AttributeType attributeType)
{
Reject.ifNull(attributeType);
String rawAttributeType = attributeType.getNameOrOID();
MatchedValuesFilter filter =
new MatchedValuesFilter(PRESENT_TYPE, rawAttributeType, null, null,
null, null, null);
filter.attributeType = attributeType;
return filter;
}
/**
* Creates a new approxMatch filter with the provided information.
*
* @param rawAttributeType The raw, unprocessed attribute type.
* @param rawAssertionValue The raw, unprocessed assertion value.
*
* @return The created approxMatch filter.
*/
public static MatchedValuesFilter createApproximateFilter(
String rawAttributeType,
ByteString rawAssertionValue)
{
Reject.ifNull(rawAttributeType,rawAssertionValue);
return new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE, rawAttributeType,
rawAssertionValue, null, null, null, null);
}
/**
* Creates a new approxMatch filter with the provided information.
*
* @param attributeType The attribute type.
* @param assertionValue The assertion value.
*
* @return The created approxMatch filter.
*/
public static MatchedValuesFilter createApproximateFilter(
AttributeType attributeType,
ByteString assertionValue)
{
Reject.ifNull(attributeType,assertionValue);
String rawAttributeType = attributeType.getNameOrOID();
MatchedValuesFilter filter =
new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE, rawAttributeType,
assertionValue, null, null, null, null);
filter.attributeType = attributeType;
filter.assertionValue = assertionValue;
return filter;
}
/**
* Creates a new extensibleMatch filter with the provided information.
*
* @param rawAttributeType The raw, unprocessed attribute type.
* @param matchingRuleID The matching rule ID.
* @param rawAssertionValue The raw, unprocessed assertion value.
*
* @return The created extensibleMatch filter.
*/
public static MatchedValuesFilter createExtensibleMatchFilter(
String rawAttributeType,
String matchingRuleID,
ByteString rawAssertionValue)
{
Reject.ifNull(rawAttributeType, matchingRuleID, rawAssertionValue);
return new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE, rawAttributeType,
rawAssertionValue, null, null, null,
matchingRuleID);
}
/**
* Creates a new extensibleMatch filter with the provided information.
*
* @param attributeType The attribute type.
* @param matchingRule The matching rule.
* @param assertionValue The assertion value.
*
* @return The created extensibleMatch filter.
*/
public static MatchedValuesFilter createExtensibleMatchFilter(
AttributeType attributeType,
MatchingRule matchingRule,
ByteString assertionValue)
{
Reject.ifNull(attributeType, matchingRule, assertionValue);
String rawAttributeType = attributeType.getNameOrOID();
String matchingRuleID = matchingRule.getOID();
MatchedValuesFilter filter =
new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE, rawAttributeType,
assertionValue, null, null, null,
matchingRuleID);
filter.attributeType = attributeType;
filter.assertionValue = assertionValue;
filter.matchingRule = matchingRule;
return filter;
}
/**
* Creates a new matched values filter from the provided LDAP filter.
*
* @param filter The LDAP filter to use for this matched values filter.
*
* @return The corresponding matched values filter.
*
* @throws LDAPException If the provided LDAP filter cannot be treated as a
* matched values filter.
*/
public static MatchedValuesFilter createFromLDAPFilter(RawFilter filter)
throws LDAPException
{
switch (filter.getFilterType())
{
case AND:
case OR:
case NOT:
// These filter types cannot be used in a matched values filter.
LocalizableMessage message = ERR_MVFILTER_INVALID_LDAP_FILTER_TYPE.get(
filter, filter.getFilterType());
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
case EQUALITY:
return new MatchedValuesFilter(EQUALITY_MATCH_TYPE,
filter.getAttributeType(),
filter.getAssertionValue(), null, null,
null, null);
case SUBSTRING:
return new MatchedValuesFilter(SUBSTRINGS_TYPE,
filter.getAttributeType(), null,
filter.getSubInitialElement(),
filter.getSubAnyElements(),
filter.getSubFinalElement(), null);
case GREATER_OR_EQUAL:
return new MatchedValuesFilter(GREATER_OR_EQUAL_TYPE,
filter.getAttributeType(),
filter.getAssertionValue(), null, null,
null, null);
case LESS_OR_EQUAL:
return new MatchedValuesFilter(LESS_OR_EQUAL_TYPE,
filter.getAttributeType(),
filter.getAssertionValue(), null, null,
null, null);
case PRESENT:
return new MatchedValuesFilter(PRESENT_TYPE, filter.getAttributeType(),
null, null, null, null, null);
case APPROXIMATE_MATCH:
return new MatchedValuesFilter(APPROXIMATE_MATCH_TYPE,
filter.getAttributeType(),
filter.getAssertionValue(), null, null,
null, null);
case EXTENSIBLE_MATCH:
if (filter.getDNAttributes())
{
// This cannot be represented in a matched values filter.
message = ERR_MVFILTER_INVALID_DN_ATTRIBUTES_FLAG.get(filter);
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
}
else
{
return new MatchedValuesFilter(EXTENSIBLE_MATCH_TYPE,
filter.getAttributeType(),
filter.getAssertionValue(), null, null,
null, filter.getMatchingRuleID());
}
default:
message = ERR_MVFILTER_INVALID_LDAP_FILTER_TYPE.get(filter, filter.getFilterType());
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
}
}
/**
* Encodes this matched values filter as an ASN.1 element.
*
* @param writer The ASN1Writer to use to encode this matched values filter.
* @throws IOException if an error occurs while encoding.
*/
public void encode(ASN1Writer writer) throws IOException
{
switch (matchType)
{
case EQUALITY_MATCH_TYPE:
case GREATER_OR_EQUAL_TYPE:
case LESS_OR_EQUAL_TYPE:
case APPROXIMATE_MATCH_TYPE:
// These will all be encoded in the same way.
writer.writeStartSequence(matchType);
writer.writeOctetString(rawAttributeType);
writer.writeOctetString(rawAssertionValue);
writer.writeEndSequence();
return;
case SUBSTRINGS_TYPE:
writer.writeStartSequence(matchType);
writer.writeOctetString(rawAttributeType);
writer.writeStartSequence();
if (subInitial != null)
{
writer.writeOctetString(TYPE_SUBINITIAL, subInitial);
}
if (subAny != null)
{
for (ByteString s : subAny)
{
writer.writeOctetString(TYPE_SUBANY, s);
}
}
if (subFinal != null)
{
writer.writeOctetString(TYPE_SUBFINAL, subFinal);
}
writer.writeEndSequence();
writer.writeEndSequence();
return;
case PRESENT_TYPE:
writer.writeOctetString(matchType, rawAttributeType);
return;
case EXTENSIBLE_MATCH_TYPE:
writer.writeStartSequence(matchType);
if (matchingRuleID != null)
{
writer.writeOctetString(TYPE_MATCHING_RULE_ID, matchingRuleID);
}
if (rawAttributeType != null)
{
writer.writeOctetString(TYPE_MATCHING_RULE_TYPE, rawAttributeType);
}
writer.writeOctetString(TYPE_MATCHING_RULE_VALUE, rawAssertionValue);
writer.writeEndSequence();
return;
default:
}
}
/**
* Decodes the provided ASN.1 element as a matched values filter item.
*
* @param reader The ASN.1 reader.
*
* @return The decoded matched values filter.
*
* @throws LDAPException If a problem occurs while attempting to decode the
* filter item.
*/
public static MatchedValuesFilter decode(ASN1Reader reader)
throws LDAPException
{
byte type;
try
{
type = reader.peekType();
}
catch(Exception e)
{
// TODO: Need a better message.
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR,
ERR_MVFILTER_INVALID_ELEMENT_TYPE.get(e));
}
switch (type)
{
case EQUALITY_MATCH_TYPE:
case GREATER_OR_EQUAL_TYPE:
case LESS_OR_EQUAL_TYPE:
case APPROXIMATE_MATCH_TYPE:
// These will all be decoded in the same manner. The element must be a
// sequence consisting of the attribute type and assertion value.
try
{
reader.readStartSequence();
String rawAttributeType = reader.readOctetStringAsString();
ByteString rawAssertionValue = reader.readOctetString();
reader.readEndSequence();
return new MatchedValuesFilter(type, rawAttributeType,
rawAssertionValue, null, null, null, null);
}
catch (Exception e)
{
logger.traceException(e);
LocalizableMessage message =
ERR_MVFILTER_CANNOT_DECODE_AVA.get(getExceptionMessage(e));
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
}
case SUBSTRINGS_TYPE:
// This must be a sequence of two elements, where the second is a
// sequence of substring types.
try
{
reader.readStartSequence();
String rawAttributeType = reader.readOctetStringAsString();
reader.readStartSequence();
if(!reader.hasNextElement())
{
LocalizableMessage message = ERR_MVFILTER_NO_SUBSTRING_ELEMENTS.get();
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
}
ByteString subInitial = null;
ArrayList<ByteString> subAny = null;
ByteString subFinal = null;
if(reader.hasNextElement() &&
reader.peekType() == TYPE_SUBINITIAL)
{
subInitial = reader.readOctetString();
}
while(reader.hasNextElement() &&
reader.peekType() == TYPE_SUBANY)
{
if(subAny == null)
{
subAny = new ArrayList<>();
}
subAny.add(reader.readOctetString());
}
if(reader.hasNextElement() &&
reader.peekType() == TYPE_SUBFINAL)
{
subFinal = reader.readOctetString();
}
reader.readEndSequence();
reader.readEndSequence();
return new MatchedValuesFilter(type, rawAttributeType,
null, subInitial, subAny, subFinal, null);
}
catch (LDAPException le)
{
throw le;
}
catch (Exception e)
{
logger.traceException(e);
LocalizableMessage message =
ERR_MVFILTER_CANNOT_DECODE_SUBSTRINGS.get(getExceptionMessage(e));
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
}
case PRESENT_TYPE:
// The element must be an ASN.1 octet string holding the attribute type.
try
{
String rawAttributeType = reader.readOctetStringAsString();
return new MatchedValuesFilter(type, rawAttributeType,
null, null, null, null, null);
}
catch (Exception e)
{
logger.traceException(e);
LocalizableMessage message = ERR_MVFILTER_CANNOT_DECODE_PRESENT_TYPE.get(
getExceptionMessage(e));
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
}
case EXTENSIBLE_MATCH_TYPE:
// This must be a two or three element sequence with an assertion value
// as the last element and an attribute type and/or matching rule ID as
// the first element(s).
try
{
reader.readStartSequence();
String rawAttributeType = null;
String matchingRuleID = null;
if(reader.peekType() == TYPE_MATCHING_RULE_ID)
{
matchingRuleID = reader.readOctetStringAsString();
}
if(matchingRuleID == null ||
reader.peekType() == TYPE_MATCHING_RULE_TYPE)
{
rawAttributeType = reader.readOctetStringAsString();
}
ByteString rawAssertionValue = reader.readOctetString();
reader.readEndSequence();
return new MatchedValuesFilter(type, rawAttributeType,
rawAssertionValue, null, null, null,
matchingRuleID);
}
catch (Exception e)
{
logger.traceException(e);
LocalizableMessage message = ERR_MVFILTER_CANNOT_DECODE_EXTENSIBLE_MATCH.get(
getExceptionMessage(e));
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
}
default:
LocalizableMessage message =
ERR_MVFILTER_INVALID_ELEMENT_TYPE.get(byteToHex(type));
throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
}
}
/**
* Retrieves the match type for this matched values filter.
*
* @return The match type for this matched values filter.
*/
public byte getMatchType()
{
return matchType;
}
/**
* Retrieves the raw, unprocessed attribute type for this matched values
* filter.
*
* @return The raw, unprocessed attribute type for this matched values
* filter, or <CODE>null</CODE> if there is none.
*/
public String getRawAttributeType()
{
return rawAttributeType;
}
/**
* Retrieves the attribute type for this matched values filter.
*
* @return The attribute type for this matched values filter, or
* <CODE>null</CODE> if there is none.
*/
public AttributeType getAttributeType()
{
if (attributeType == null && rawAttributeType != null)
{
String lowerName = toLowerCase(rawAttributeType);
attributeType = DirectoryServer.getAttributeTypeOrDefault(lowerName, rawAttributeType);
}
return attributeType;
}
/**
* Retrieves the raw, unprocessed assertion value for this matched values
* filter.
*
* @return The raw, unprocessed assertion value for this matched values
* filter, or <CODE>null</CODE> if there is none.
*/
public ByteString getRawAssertionValue()
{
return rawAssertionValue;
}
/**
* Retrieves the assertion value for this matched values filter.
*
* @return The assertion value for this matched values filter, or
* <CODE>null</CODE> if there is none.
*/
public ByteString getAssertionValue()
{
if (assertionValue == null && rawAssertionValue != null)
{
assertionValue = rawAssertionValue;
}
return assertionValue;
}
/**
* Retrieves the subInitial element for this matched values filter.
*
* @return The subInitial element for this matched values filter, or
* <CODE>null</CODE> if there is none.
*/
public ByteString getSubInitialElement()
{
return subInitial;
}
private Assertion getSubstringAssertion() {
if (substringAssertion == null)
{
try
{
MatchingRule rule = getSubstringMatchingRule();
if (rule != null)
{
substringAssertion = rule.getSubstringAssertion(subInitial, subAny, subFinal);
}
}
catch (DecodeException e)
{
logger.traceException(e);
}
}
return substringAssertion;
}
/**
* Retrieves the set of subAny elements for this matched values filter.
*
* @return The set of subAny elements for this matched values filter. If
* there are none, then the return value may be either
* <CODE>null</CODE> or an empty list.
*/
public List<ByteString> getSubAnyElements()
{
return subAny;
}
/**
* Retrieves the subFinal element for this matched values filter.
*
* @return The subFinal element for this matched values filter, or
* <CODE>null</CODE> if there is none.
*/
public ByteString getSubFinalElement()
{
return subFinal;
}
/**
* Retrieves the matching rule ID for this matched values filter.
*
* @return The matching rule ID for this matched values filter, or
* <CODE>null</CODE> if there is none.
*/
public String getMatchingRuleID()
{
return matchingRuleID;
}
/**
* Retrieves the matching rule for this matched values filter.
*
* @return The matching rule for this matched values filter, or
* <CODE>null</CODE> if there is none.
*/
public MatchingRule getMatchingRule()
{
if (matchingRule == null && matchingRuleID != null)
{
matchingRule = DirectoryServer.getMatchingRule(toLowerCase(matchingRuleID));
}
return matchingRule;
}
/**
* Retrieves the approximate matching rule that should be used for this
* matched values filter.
*
* @return The approximate matching rule that should be used for this matched
* values filter, or <CODE>null</CODE> if there is none.
*/
public MatchingRule getApproximateMatchingRule()
{
if (approximateMatchingRule == null)
{
AttributeType attrType = getAttributeType();
if (attrType != null)
{
approximateMatchingRule = attrType.getApproximateMatchingRule();
}
}
return approximateMatchingRule;
}
/**
* Retrieves the equality matching rule that should be used for this matched
* values filter.
*
* @return The equality matching rule that should be used for this matched
* values filter, or <CODE>null</CODE> if there is none.
*/
public MatchingRule getEqualityMatchingRule()
{
if (equalityMatchingRule == null)
{
AttributeType attrType = getAttributeType();
if (attrType != null)
{
equalityMatchingRule = attrType.getEqualityMatchingRule();
}
}
return equalityMatchingRule;
}
/**
* Retrieves the ordering matching rule that should be used for this matched
* values filter.
*
* @return The ordering matching rule that should be used for this matched
* values filter, or <CODE>null</CODE> if there is none.
*/
public MatchingRule getOrderingMatchingRule()
{
if (orderingMatchingRule == null)
{
AttributeType attrType = getAttributeType();
if (attrType != null)
{
orderingMatchingRule = attrType.getOrderingMatchingRule();
}
}
return orderingMatchingRule;
}
/**
* Retrieves the substring matching rule that should be used for this matched
* values filter.
*
* @return The substring matching rule that should be used for this matched
* values filter, or <CODE>null</CODE> if there is none.
*/
public MatchingRule getSubstringMatchingRule()
{
if (substringMatchingRule == null)
{
AttributeType attrType = getAttributeType();
if (attrType != null)
{
substringMatchingRule = attrType.getSubstringMatchingRule();
}
}
return substringMatchingRule;
}
/**
* Decodes all components of the matched values filter so that they can be
* referenced as member variables.
*/
private void fullyDecode()
{
if (! decoded)
{
getAttributeType();
getAssertionValue();
getSubstringAssertion();
getMatchingRule();
getApproximateMatchingRule();
getEqualityMatchingRule();
getOrderingMatchingRule();
getSubstringMatchingRule();
decoded = true;
}
}
/**
* Indicates whether the specified attribute value matches the criteria
* defined in this matched values filter.
*
* @param type The attribute type with which the provided value is
* associated.
* @param value The attribute value for which to make the determination.
*
* @return <CODE>true</CODE> if the specified attribute value matches the
* criteria defined in this matched values filter, or
* <CODE>false</CODE> if not.
*/
public boolean valueMatches(AttributeType type, ByteString value)
{
fullyDecode();
switch (matchType)
{
case EQUALITY_MATCH_TYPE:
if (attributeType != null
&& attributeType.equals(type)
&& rawAssertionValue != null
&& value != null
&& equalityMatchingRule != null)
{
return matches(equalityMatchingRule, value, rawAssertionValue);
}
return false;
case SUBSTRINGS_TYPE:
if (attributeType != null
&& attributeType.equals(type)
&& substringAssertion != null)
{
try
{
return substringAssertion.matches(substringMatchingRule.normalizeAttributeValue(value)).toBoolean();
}
catch (Exception e)
{
logger.traceException(e);
}
}
return false;
case GREATER_OR_EQUAL_TYPE:
if (attributeType != null
&& attributeType.equals(type)
&& assertionValue != null
&& value != null
&& orderingMatchingRule != null)
{
try
{
ByteString normValue = orderingMatchingRule.normalizeAttributeValue(value);
Assertion assertion = orderingMatchingRule.getGreaterOrEqualAssertion(assertionValue);
return assertion.matches(normValue).toBoolean();
}
catch (DecodeException e)
{
logger.traceException(e);
}
}
return false;
case LESS_OR_EQUAL_TYPE:
if (attributeType != null
&& attributeType.equals(type)
&& assertionValue != null
&& value != null
&& orderingMatchingRule != null)
{
try
{
ByteString normValue = orderingMatchingRule.normalizeAttributeValue(value);
Assertion assertion = orderingMatchingRule.getLessOrEqualAssertion(assertionValue);
return assertion.matches(normValue).toBoolean();
}
catch (DecodeException e)
{
logger.traceException(e);
}
}
return false;
case PRESENT_TYPE:
return attributeType != null && attributeType.equals(type);
case APPROXIMATE_MATCH_TYPE:
if (attributeType != null
&& attributeType.equals(type)
&& assertionValue != null
&& value != null
&& approximateMatchingRule != null)
{
return matches(approximateMatchingRule, value, assertionValue);
}
return false;
case EXTENSIBLE_MATCH_TYPE:
if (attributeType == null)
{
return matches(matchingRule, value, assertionValue);
}
else if (!attributeType.equals(type))
{
return false;
}
return matches(equalityMatchingRule, value, rawAssertionValue);
default:
return false;
}
}
private boolean matches(MatchingRule matchingRule, ByteString value, ByteString assertionValue)
{
if (matchingRule == null || value == null || assertionValue == null)
{
return false;
}
try
{
ByteString normValue = matchingRule.normalizeAttributeValue(value);
Assertion assertion = matchingRule.getAssertion(assertionValue);
return assertion.matches(normValue).toBoolean();
}
catch (DecodeException e)
{
logger.traceException(e);
return false;
}
}
/**
* Retrieves a string representation of this matched values filter, as an RFC
* 2254-compliant filter string.
*
* @return A string representation of this matched values filter.
*/
@Override
public String toString()
{
StringBuilder buffer = new StringBuilder();
toString(buffer);
return buffer.toString();
}
/**
* Appends a string representation of this matched values filter, as an RFC
* 2254-compliant filter string, to the provided buffer.
*
* @param buffer The buffer to which the filter string should be appended.
*/
public void toString(StringBuilder buffer)
{
switch (matchType)
{
case EQUALITY_MATCH_TYPE:
appendAttributeTypeAndAssertion(buffer, "=");
break;
case SUBSTRINGS_TYPE:
buffer.append("(");
buffer.append(rawAttributeType);
buffer.append("=");
if (subInitial != null)
{
RawFilter.valueToFilterString(buffer, subInitial);
}
if (subAny != null)
{
for (ByteString s : subAny)
{
buffer.append("*");
RawFilter.valueToFilterString(buffer, s);
}
}
buffer.append("*");
if (subFinal != null)
{
RawFilter.valueToFilterString(buffer, subFinal);
}
buffer.append(")");
break;
case GREATER_OR_EQUAL_TYPE:
appendAttributeTypeAndAssertion(buffer, ">=");
break;
case LESS_OR_EQUAL_TYPE:
appendAttributeTypeAndAssertion(buffer, "<=");
break;
case PRESENT_TYPE:
buffer.append("(");
buffer.append(rawAttributeType);
buffer.append("=*)");
break;
case APPROXIMATE_MATCH_TYPE:
appendAttributeTypeAndAssertion(buffer, "~=");
break;
case EXTENSIBLE_MATCH_TYPE:
buffer.append("(");
if (rawAttributeType != null)
{
buffer.append(rawAttributeType);
}
if (matchingRuleID != null)
{
buffer.append(":");
buffer.append(matchingRuleID);
}
buffer.append(":=");
RawFilter.valueToFilterString(buffer, rawAssertionValue);
buffer.append(")");
break;
}
}
private void appendAttributeTypeAndAssertion(StringBuilder buffer, String operator)
{
buffer.append("(");
buffer.append(rawAttributeType);
buffer.append(operator);
RawFilter.valueToFilterString(buffer, rawAssertionValue);
buffer.append(")");
}
}