From e67f90aeff42363b892ae478f935b00c7e64e0a8 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Thu, 06 Mar 2014 13:00:09 +0000
Subject: [PATCH] OPENDJ-1308 (CR-3138) Migrate schema support
---
opendj-sdk/opendj-core/clirr-ignored-api-changes.xml | 20 ++
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexingOptions.java | 41 ++++
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java | 13 +
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CertificateExactMatchingRuleImpl.java | 5
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/Assertion.java | 19 +
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractApproximateMatchingRuleImpl.java | 8
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractOrderingMatchingRuleImpl.java | 26 ++
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java | 44 ++++
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EqualLengthApproximateMatchingRuleImpl.java | 6
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleImpl.java | 15 +
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractEqualityMatchingRuleImpl.java | 8
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java | 69 ++++++
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java | 10 +
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexQueryFactory.java | 117 +++++++++++
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java | 145 +++++++++++++
15 files changed, 536 insertions(+), 10 deletions(-)
diff --git a/opendj-sdk/opendj-core/clirr-ignored-api-changes.xml b/opendj-sdk/opendj-core/clirr-ignored-api-changes.xml
index e02b4ef..b7c314d 100644
--- a/opendj-sdk/opendj-core/clirr-ignored-api-changes.xml
+++ b/opendj-sdk/opendj-core/clirr-ignored-api-changes.xml
@@ -178,4 +178,24 @@
<method>org.forgerock.opendj.ldap.LDAPOptions setDecodeOptions(org.forgerock.opendj.ldap.DecodeOptions)</method>
<justification>OPENDJ-1197: Method return type has changed due to reification</justification>
</difference>
+
+ <difference>
+ <className>org/forgerock/opendj/ldap/Assertion</className>
+ <differenceType>7012</differenceType>
+ <method>java.lang.Object createIndexQuery(org.forgerock.opendj.ldap.spi.IndexQueryFactory)</method>
+ <justification>OPENDJ-1308 Migrate schema support: allows decoupling indexing from a specific backend</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/schema/MatchingRuleImpl</className>
+ <differenceType>7012</differenceType>
+ <method>org.forgerock.opendj.ldap.spi.Indexer getIndexer()</method>
+ <justification>OPENDJ-1308 Migrate schema support: allows decoupling indexing from a specific backend</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/schema/MatchingRuleImpl</className>
+ <differenceType>7012</differenceType>
+ <method>boolean isIndexingSupported()</method>
+ <justification>OPENDJ-1308 Migrate schema support: allows decoupling indexing from a specific backend</justification>
+ </difference>
+
</differences>
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/Assertion.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/Assertion.java
index e736b20..59ebf9a 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/Assertion.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/Assertion.java
@@ -26,10 +26,13 @@
*/
package org.forgerock.opendj.ldap;
+import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
+
/**
* A compiled attribute value assertion.
*/
public interface Assertion {
+
/**
* Indicates whether the provided attribute value should be considered a
* match for this assertion value according to the matching rule.
@@ -41,4 +44,20 @@
* match, or {@code UNDEFINED} if the result is undefined.
*/
ConditionResult matches(ByteSequence normalizedAttributeValue);
+
+ /**
+ * Returns an index query appropriate for the provided attribute
+ * value assertion.
+ *
+ * @param <T>
+ * The type of index query created by the {@code factory}.
+ * @param factory
+ * The index query factory which should be used to
+ * construct the index query.
+ * @return The index query appropriate for the provided attribute
+ * value assertion.
+ * @throws DecodeException
+ * If an error occurs while generating the index query.
+ */
+ <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException;
}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractApproximateMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractApproximateMatchingRuleImpl.java
index b1f11ba..ab84c38 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractApproximateMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractApproximateMatchingRuleImpl.java
@@ -28,6 +28,7 @@
import org.forgerock.opendj.ldap.Assertion;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.spi.Indexer;
/**
* This class implements an approximate matching rule that matches normalized
@@ -35,6 +36,8 @@
*/
abstract class AbstractApproximateMatchingRuleImpl extends AbstractMatchingRuleImpl {
+ private final Indexer indexer = new DefaultIndexer("approximate");
+
AbstractApproximateMatchingRuleImpl() {
// Nothing to do.
}
@@ -45,4 +48,9 @@
return DefaultAssertion.approximate(normalizeAttributeValue(schema, assertionValue));
}
+ /** {@inheritDoc} */
+ @Override
+ public Indexer getIndexer() {
+ return indexer;
+ }
}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractEqualityMatchingRuleImpl.java
index 84d19ed..6744f3b 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractEqualityMatchingRuleImpl.java
@@ -28,6 +28,7 @@
import org.forgerock.opendj.ldap.Assertion;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.spi.Indexer;
/**
* This class implements an equality matching rule that matches normalized
@@ -35,6 +36,8 @@
*/
abstract class AbstractEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl {
+ private final Indexer indexer = new DefaultIndexer("equality");
+
AbstractEqualityMatchingRuleImpl() {
// Nothing to do.
}
@@ -45,4 +48,9 @@
return DefaultAssertion.equality(normalizeAttributeValue(schema, assertionValue));
}
+ /** {@inheritDoc} */
+ @Override
+ public Indexer getIndexer() {
+ return indexer;
+ }
}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
index 5a60314..2dd602f 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
@@ -26,13 +26,18 @@
*/
package org.forgerock.opendj.ldap.schema;
+import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import org.forgerock.opendj.ldap.Assertion;
import org.forgerock.opendj.ldap.ByteSequence;
+import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
+import org.forgerock.opendj.ldap.spi.Indexer;
+import org.forgerock.opendj.ldap.spi.IndexingOptions;
/**
* This class implements a default equality or approximate matching rule that
@@ -41,7 +46,7 @@
abstract class AbstractMatchingRuleImpl implements MatchingRuleImpl {
static final class DefaultAssertion implements Assertion {
- /** The ID of the DB index that to use with this assertion.*/
+ /** The ID of the DB index to use with this assertion.*/
private final String indexID;
private final ByteSequence normalizedAssertionValue;
@@ -61,12 +66,42 @@
public ConditionResult matches(final ByteSequence attributeValue) {
return ConditionResult.valueOf(normalizedAssertionValue.equals(attributeValue));
}
+
+ public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException {
+ return factory.createExactMatchQuery(indexID, normalizedAssertionValue);
+ }
}
+ final class DefaultIndexer implements Indexer {
+ /** The ID of the DB index to use with this indexer.*/
+ private final String indexID;
+
+ DefaultIndexer(String indexID) {
+ this.indexID = indexID;
+ }
+
+ @Override
+ public void createKeys(Schema schema, ByteSequence value, IndexingOptions options, Collection<ByteString> keys)
+ throws DecodeException {
+ keys.add(normalizeAttributeValue(schema, value));
+ }
+
+ @Override
+ public String getIndexID() {
+ return indexID;
+ }
+ };
+
private static final Assertion UNDEFINED_ASSERTION = new Assertion() {
public ConditionResult matches(final ByteSequence attributeValue) {
return ConditionResult.UNDEFINED;
}
+
+ public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException {
+ // Subclassing this class will always work, albeit inefficiently.
+ // This is better than throwing an exception for no good reason.
+ return factory.createMatchAllQuery();
+ }
};
private static final Comparator<ByteSequence> DEFAULT_COMPARATOR =
@@ -104,4 +139,11 @@
throws DecodeException {
return UNDEFINED_ASSERTION;
}
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isIndexingSupported() {
+ return getIndexer() != null;
+ }
+
}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractOrderingMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractOrderingMatchingRuleImpl.java
index 5d8a171..741172b 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractOrderingMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractOrderingMatchingRuleImpl.java
@@ -31,12 +31,17 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
+import org.forgerock.opendj.ldap.spi.Indexer;
/**
* This class implements a default ordering matching rule that matches
* normalized values in byte order.
*/
abstract class AbstractOrderingMatchingRuleImpl extends AbstractMatchingRuleImpl {
+
+ private final Indexer indexer = new DefaultIndexer("ordering");
+
AbstractOrderingMatchingRuleImpl() {
// Nothing to do.
}
@@ -48,6 +53,11 @@
public ConditionResult matches(final ByteSequence attributeValue) {
return ConditionResult.valueOf(attributeValue.compareTo(normAssertion) < 0);
}
+
+ @Override
+ public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException {
+ return factory.createRangeMatchQuery("ordering", ByteString.empty(), normAssertion, false, false);
+ }
};
}
@@ -59,6 +69,11 @@
public ConditionResult matches(final ByteSequence attributeValue) {
return ConditionResult.valueOf(attributeValue.compareTo(normAssertion) >= 0);
}
+
+ @Override
+ public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException {
+ return factory.createRangeMatchQuery("ordering", normAssertion, ByteString.empty(), true, false);
+ }
};
}
@@ -70,6 +85,17 @@
public ConditionResult matches(final ByteSequence attributeValue) {
return ConditionResult.valueOf(attributeValue.compareTo(normAssertion) <= 0);
}
+
+ @Override
+ public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException {
+ return factory.createRangeMatchQuery("ordering", ByteString.empty(), normAssertion, false, true);
+ }
};
}
+
+ /** {@inheritDoc} */
+ @Override
+ public Indexer getIndexer() {
+ return indexer;
+ }
}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java
index c04b5e1..c825794 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractSubstringMatchingRuleImpl.java
@@ -28,8 +28,10 @@
import static com.forgerock.opendj.ldap.CoreMessages.*;
+import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
+import java.util.TreeSet;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.Assertion;
@@ -38,6 +40,9 @@
import org.forgerock.opendj.ldap.ByteStringBuilder;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
+import org.forgerock.opendj.ldap.spi.Indexer;
+import org.forgerock.opendj.ldap.spi.IndexingOptions;
import com.forgerock.opendj.util.SubstringReader;
@@ -46,18 +51,34 @@
* normalized substring assertion values in byte order.
*/
abstract class AbstractSubstringMatchingRuleImpl extends AbstractMatchingRuleImpl {
- static class DefaultSubstringAssertion implements Assertion {
+
+ /**
+ * Default assertion implementation for substring matching rules.
+ * For example, with the assertion value "initial*any1*any2*any3*final",
+ * the assertion will be decomposed like this:
+ * <ul>
+ * <li>normInitial will contain "initial"</li>
+ * <li>normAnys will contain [ "any1", "any2", "any3" ]</li>
+ * <li>normFinal will contain "final"</li>
+ * </ul>
+ */
+ static final class DefaultSubstringAssertion implements Assertion {
+ /** Normalized substring for the text before the first '*' character. */
private final ByteString normInitial;
+ /** Normalized substrings for all text chunks in between '*' characters. */
private final ByteString[] normAnys;
+ /** Normalized substring for the text after the last '*' character. */
private final ByteString normFinal;
- protected DefaultSubstringAssertion(final ByteString normInitial,
+ private DefaultSubstringAssertion(final ByteString normInitial,
final ByteString[] normAnys, final ByteString normFinal) {
this.normInitial = normInitial;
this.normAnys = normAnys;
this.normFinal = normFinal;
}
+ /** {@inheritDoc} */
+ @Override
public ConditionResult matches(final ByteSequence attributeValue) {
final int valueLength = attributeValue.length();
@@ -125,12 +146,118 @@
return ConditionResult.TRUE;
}
+
+ /** {@inheritDoc} */
+ @Override
+ public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException {
+ final Collection<T> subqueries = new LinkedList<T>();
+ if (normInitial != null) {
+ // relies on the fact that equality indexes are also ordered
+ subqueries.add(rangeMatch(factory, "equality", normInitial));
+ }
+ if (normAnys != null) {
+ for (ByteString normAny : normAnys) {
+ substringMatch(factory, normAny, subqueries);
+ }
+ }
+ if (normFinal != null) {
+ substringMatch(factory, normFinal, subqueries);
+ }
+ if (normInitial != null) {
+ // Add this one last to minimize the risk to run the same search twice
+ // (possible overlapping with the use of equality index at the start of this method)
+ substringMatch(factory, normInitial, subqueries);
+ }
+ return factory.createIntersectionQuery(subqueries);
+ }
+
+ private <T> T rangeMatch(IndexQueryFactory<T> factory, String indexID, ByteSequence lower) {
+ // Iterate through all the keys that have this value as the prefix.
+
+ // Set the upper bound for a range search.
+ // We need a key for the upper bound that is of equal length
+ // but slightly greater than the lower bound.
+ final ByteStringBuilder upper = new ByteStringBuilder(lower);
+
+ for (int i = upper.length() - 1; i >= 0; i--) {
+ if (upper.byteAt(i) == 0xFF) {
+ // We have to carry the overflow to the more significant byte.
+ upper.setByte(i, (byte) 0);
+ } else {
+ // No overflow, we can stop.
+ upper.setByte(i, (byte) (upper.byteAt(i) + 1));
+ break;
+ }
+ }
+
+ // Read the range: lower <= keys < upper.
+ return factory.createRangeMatchQuery(indexID, lower, upper, true, false);
+ }
+
+ private <T> void substringMatch(final IndexQueryFactory<T> factory, final ByteString normSubstring,
+ final Collection<T> subqueries) {
+ int substrLength = factory.getIndexingOptions().substringKeySize();
+
+ // There are two cases, depending on whether the user-provided
+ // substring is smaller than the configured index substring length or not.
+ if (normSubstring.length() < substrLength) {
+ subqueries.add(rangeMatch(factory, "substring", normSubstring));
+ } else {
+ // Break the value up into fragments of length equal to the
+ // index substring length, and read those keys.
+
+ // Eliminate duplicates by putting the keys into a set.
+ final TreeSet<ByteSequence> substringKeys = new TreeSet<ByteSequence>();
+
+ // Example: The value is ABCDE and the substring length is 3.
+ // We produce the keys ABC BCD CDE.
+ for (int first = 0, last = substrLength;
+ last <= normSubstring.length(); first++, last++) {
+ substringKeys.add(normSubstring.subSequence(first, first + substrLength));
+ }
+
+ for (ByteSequence key : substringKeys) {
+ subqueries.add(factory.createExactMatchQuery("substring", key));
+ }
+ }
+ }
+
}
+ final class SubstringIndexer implements Indexer {
+
+ /** {@inheritDoc} */
+ @Override
+ public void createKeys(Schema schema, ByteSequence value, IndexingOptions options, Collection<ByteString> keys)
+ throws DecodeException {
+ final ByteString normValue = normalizeAttributeValue(schema, value);
+ final int substringKeySize = options.substringKeySize();
+
+ // Example: The value is ABCDE and the substring length is 3.
+ // We produce the keys ABC BCD CDE DE E
+ // To find values containing a short substring such as DE,
+ // iterate through keys with prefix DE. To find values
+ // containing a longer substring such as BCDE, read keys BCD and CDE.
+ for (int i = 0, remain = normValue.length(); remain > 0; i++, remain--) {
+ int len = Math.min(substringKeySize, remain);
+ keys.add(normValue.subSequence(i, i + len));
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getIndexID() {
+ return "substring";
+ }
+ }
+
+ private SubstringIndexer substringIndexer = new SubstringIndexer();
+
AbstractSubstringMatchingRuleImpl() {
// Nothing to do.
}
+ /** {@inheritDoc} */
@Override
public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue)
throws DecodeException {
@@ -143,7 +270,6 @@
List<ByteSequence> anyStrings = null;
final String valueString = assertionValue.toString();
-
if (valueString.length() == 1 && valueString.charAt(0) == '*') {
return getSubstringAssertion(schema, initialString, anyStrings, finalString);
}
@@ -156,8 +282,7 @@
initialString = normalizeSubString(schema, bytes);
}
if (reader.remaining() == 0) {
- throw DecodeException.error(WARN_ATTR_SYNTAX_SUBSTRING_NO_WILDCARDS.get(assertionValue
- .toString()));
+ throw DecodeException.error(WARN_ATTR_SYNTAX_SUBSTRING_NO_WILDCARDS.get(assertionValue));
}
while (true) {
reader.read();
@@ -165,7 +290,7 @@
if (reader.remaining() > 0) {
if (bytes.length() == 0) {
throw DecodeException.error(WARN_ATTR_SYNTAX_SUBSTRING_CONSECUTIVE_WILDCARDS
- .get(assertionValue.toString(), reader.pos()));
+ .get(assertionValue, reader.pos()));
}
if (anyStrings == null) {
anyStrings = new LinkedList<ByteSequence>();
@@ -182,6 +307,7 @@
return getSubstringAssertion(schema, initialString, anyStrings, finalString);
}
+ /** {@inheritDoc} */
@Override
public Assertion getSubstringAssertion(final Schema schema, final ByteSequence subInitial,
final List<? extends ByteSequence> subAnyElements, final ByteSequence subFinal)
@@ -436,4 +562,11 @@
return ByteString.empty();
}
}
+
+ /** {@inheritDoc} */
+ @Override
+ public Indexer getIndexer() {
+ return substringIndexer;
+ }
+
}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CertificateExactMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CertificateExactMatchingRuleImpl.java
index 1a795f9..2ea67c6 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CertificateExactMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CertificateExactMatchingRuleImpl.java
@@ -23,7 +23,6 @@
*
* Copyright 2006-2009 Sun Microsystems, Inc.
* Portions Copyright 2013-2014 Manuel Gaupp
- * Copyright 2014 ForgeRock AS
*/
package org.forgerock.opendj.ldap.schema;
@@ -43,8 +42,8 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ByteStringBuilder;
import org.forgerock.opendj.ldap.DecodeException;
-import org.forgerock.opendj.ldap.GSERParser;
import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.GSERParser;
import com.forgerock.opendj.util.StaticUtils;
@@ -55,7 +54,7 @@
* X.509 and referenced in RFC 4523.
*/
final class CertificateExactMatchingRuleImpl
- extends AbstractMatchingRuleImpl {
+ extends AbstractEqualityMatchingRuleImpl {
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EqualLengthApproximateMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EqualLengthApproximateMatchingRuleImpl.java
index 8a16d83..9583da2 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EqualLengthApproximateMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EqualLengthApproximateMatchingRuleImpl.java
@@ -31,6 +31,7 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
/**
* This class implements an extremely simple approximate matching rule that will
@@ -46,6 +47,11 @@
public ConditionResult matches(final ByteSequence attributeValue) {
return ConditionResult.valueOf(attributeValue.length() == assertionValue.length());
}
+
+ @Override
+ public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException {
+ return factory.createExactMatchQuery("approximate", ByteString.valueOf(assertionValue.length()));
+ }
};
}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java
index 8a33b76..8bbdbd8 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java
@@ -34,6 +34,8 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
+import org.forgerock.opendj.ldap.spi.Indexer;
/**
* This class implements the keywordMatch matching rule defined in X.520. That
@@ -107,9 +109,20 @@
return false;
}
}
+
+ @Override
+ public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException {
+ return factory.createMatchAllQuery();
+ }
};
}
+ /** {@inheritDoc} */
+ @Override
+ public Indexer getIndexer() {
+ return null;
+ }
+
public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
return ByteString.valueOf(normalize(value));
}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java
index 0e7bdcc..a6a6dcb 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java
@@ -43,6 +43,7 @@
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.spi.Indexer;
/**
@@ -361,6 +362,15 @@
}
/**
+ * Returns the indexer for this matching rule.
+ *
+ * @return the indexer for this matching rule.
+ */
+ public Indexer getIndexer() {
+ return impl.getIndexer();
+ }
+
+ /**
* Returns the name or OID for this schema definition. If it has one or more
* names, then the primary name will be returned. If it does not have any
* names, then the OID will be returned.
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleImpl.java
index 28e02a0..bf74e88 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleImpl.java
@@ -33,6 +33,7 @@
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.spi.Indexer;
/**
* This interface defines the set of methods that must be implemented to define
@@ -139,4 +140,18 @@
ByteString normalizeAttributeValue(Schema schema, ByteSequence value)
throws DecodeException;
+ /**
+ * Returns the indexer for this matching rule.
+ *
+ * @return the indexer for this matching rule.
+ */
+ Indexer getIndexer();
+
+ /**
+ * Returns whether a backend can build an index for this matching rule.
+ *
+ * @return true a backend can build an index for this matching rule,
+ * false otherwise.
+ */
+ boolean isIndexingSupported();
}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexQueryFactory.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexQueryFactory.java
new file mode 100644
index 0000000..346c115
--- /dev/null
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexQueryFactory.java
@@ -0,0 +1,117 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.
+ * Portions Copyright 2014 ForgeRock AS
+ */
+package org.forgerock.opendj.ldap.spi;
+
+import java.util.Collection;
+
+import org.forgerock.opendj.ldap.ByteSequence;
+
+/**
+ * A factory for creating arbitrarily complex index queries. This
+ * interface is implemented by the underlying backend implementation
+ * and passed to extensible matching rules so that they can construct
+ * arbitrarily complex index queries.
+ *
+ * @param <T>
+ * The type of query created by this factory.
+ */
+public interface IndexQueryFactory<T> {
+
+ /**
+ * Returns a query requesting an index record matching the provided key.
+ *
+ * @param indexID
+ * An identifier of the index type.
+ * @param key
+ * A byte sequence containing the key.
+ * @return A query requesting the index record matching the key.
+ */
+ T createExactMatchQuery(String indexID, ByteSequence key);
+
+ /**
+ * Returns a query requesting all index records. A backend implementation
+ * may choose to return all or no records as part of the optimization.
+ *
+ * @return A query requesting all index records.
+ */
+ T createMatchAllQuery();
+
+ /**
+ * Returns a query requesting all index records in the specified range.
+ *
+ * @param indexID
+ * An identifier of the index type.
+ * @param lower
+ * The lower bound of the range. A 0 length byte array indicates no
+ * lower bound and the range will start from the smallest key.
+ * @param upper
+ * The upper bound of the range. A 0 length byte array indicates no
+ * upper bound and the range will end at the largest key.
+ * @param lowerIncluded
+ * true if a key exactly matching the lower bound is included in
+ * the range, false if only keys strictly greater than the lower
+ * bound are included. This value is ignored if the lower bound is
+ * not specified.
+ * @param upperIncluded
+ * true if a key exactly matching the upper bound is included in
+ * the range, false if only keys strictly less than the upper bound
+ * are included. This value is ignored if the upper bound is not
+ * specified.
+ * @return A query requesting all index records in the specified range.
+ */
+ T createRangeMatchQuery(String indexID, ByteSequence lower,
+ ByteSequence upper, boolean lowerIncluded, boolean upperIncluded);
+
+ /**
+ * Returns a query which returns the intersection of a collection of
+ * sub-queries.
+ *
+ * @param subqueries
+ * A collection of sub-queries.
+ * @return A query which returns the intersection of a collection of
+ * sub-queries.
+ */
+ T createIntersectionQuery(Collection<T> subqueries);
+
+ /**
+ * Returns a query which combines the results of a collection of
+ * sub-queries.
+ *
+ * @param subqueries
+ * A collection of sub-queries.
+ * @return A query which combines the results of a collection of
+ * sub-queries.
+ */
+ T createUnionQuery(Collection<T> subqueries);
+
+ /**
+ * Returns the indexing options for this factory.
+ *
+ * @return the indexing options for this factory.
+ */
+ IndexingOptions getIndexingOptions();
+}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java
new file mode 100644
index 0000000..b00b1ed
--- /dev/null
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java
@@ -0,0 +1,69 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.
+ */
+package org.forgerock.opendj.ldap.spi;
+
+import java.util.Collection;
+
+import org.forgerock.opendj.ldap.ByteSequence;
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.schema.Schema;
+
+/**
+ * This class is registered with a Backend and it provides call- backs
+ * for indexing attribute values. An index implementation will use
+ * this interface to create the keys for an attribute value.
+ */
+public interface Indexer {
+
+ /**
+ * Returns an index identifier associated with this indexer. An identifier
+ * should be selected based on the matching rule type. A unique identifier
+ * will map to a unique index database in the backend implementation. If
+ * multiple matching rules need to share the index database, the
+ * corresponding indexers should always use the same identifier.
+ *
+ * @return index ID A String containing the ID associated with this indexer.
+ */
+ String getIndexID();
+
+ /**
+ * Generates the set of index keys for an attribute.
+ *
+ * @param schema
+ * The schema in which the associated matching rule is defined.
+ * @param value
+ * The attribute value for which keys are required.
+ * @param options
+ * The indexing options
+ * @param keys
+ * A collection where to add the created keys.
+ * @throws DecodeException if an error occurs while normalizing the value
+ */
+ void createKeys(Schema schema, ByteSequence value, IndexingOptions options,
+ Collection<ByteString> keys) throws DecodeException;
+
+}
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexingOptions.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexingOptions.java
new file mode 100644
index 0000000..24be72f
--- /dev/null
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexingOptions.java
@@ -0,0 +1,41 @@
+/*
+ * 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 2014 ForgeRock AS
+ */
+package org.forgerock.opendj.ldap.spi;
+
+/**
+ * Contains options indicating how indexing must be performed.
+ */
+public interface IndexingOptions {
+
+ /**
+ * Returns the maximum size to use when building the keys for the
+ * "substring" index.
+ *
+ * @return the maximum size to use when building the keys for the
+ * "substring" index.
+ */
+ int substringKeySize();
+
+}
--
Gitblit v1.10.0