mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Jean-Noel Rouvignac
06.00.2014 e67f90aeff42363b892ae478f935b00c7e64e0a8
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>
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;
}
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;
    }
}
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;
    }
}
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;
    }
}
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;
    }
}
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;
    }
}
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();
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()));
            }
        };
    }
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));
    }
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.
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();
}
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexQueryFactory.java
New file
@@ -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();
}
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/Indexer.java
New file
@@ -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;
}
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/IndexingOptions.java
New file
@@ -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();
}