From 89485d11a14d27f7b0578695d436335de8bc58bd Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Mon, 10 Nov 2014 14:09:13 +0000
Subject: [PATCH] OPENDJ-1591 (CR-5206) Switch to SDK matching rules

---
 /dev/null                                                                                                 |   89 ---
 opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java                          |  672 +++++++++++---------------
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java |  403 ++++++----------
 opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexFilter.java                             |  292 ++---------
 opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java                     |    3 
 5 files changed, 502 insertions(+), 957 deletions(-)

diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
deleted file mode 100644
index 290f353..0000000
--- a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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 2014 ForgeRock AS
- */
-package org.opends.server.backends.jeb;
-
-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.MatchingRule;
-import org.forgerock.opendj.ldap.schema.Schema;
-import org.forgerock.opendj.ldap.spi.Indexer;
-import org.forgerock.opendj.ldap.spi.IndexingOptions;
-import org.opends.server.types.AttributeType;
-
-/**
- * An implementation of an Indexer for attribute approximate matching.
- */
-public class ApproximateIndexer implements Indexer
-{
-
-  /**
-   * The attribute type approximate matching rule.
-   */
-  private final MatchingRule approximateRule;
-
-  /**
-   * Create a new attribute approximate indexer for the given index
-   * configuration.
-   * @param attributeType The attribute type for which an indexer is
-   * required.
-   */
-  public ApproximateIndexer(AttributeType attributeType)
-  {
-    this.approximateRule = attributeType.getApproximateMatchingRule();
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public String getIndexID()
-  {
-    return "approximate";
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void createKeys(Schema schema, ByteSequence value,
-      IndexingOptions options, Collection<ByteString> keys)
-      throws DecodeException
-  {
-    keys.add(approximateRule.normalizeAttributeValue(value));
-  }
-
-}
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
index 978f519..1e8ea08 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
@@ -38,13 +38,13 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
 import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.schema.MatchingRule;
 import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
 import org.forgerock.opendj.ldap.spi.IndexingOptions;
 import org.forgerock.util.Utils;
 import org.opends.server.admin.server.ConfigurationChangeListener;
 import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn.IndexType;
 import org.opends.server.admin.std.server.LocalDBIndexCfg;
-import org.forgerock.opendj.ldap.schema.MatchingRule;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.monitors.DatabaseEnvironmentMonitor;
 import org.opends.server.types.*;
@@ -76,16 +76,41 @@
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
+  /** Type of the index filter. */
+  static enum IndexFilterType
+  {
+    /** Equality. */
+    EQUALITY(IndexType.EQUALITY),
+    /** Presence. */
+    PRESENCE(IndexType.PRESENCE),
+    /** Ordering. */
+    GREATER_OR_EQUAL(IndexType.ORDERING),
+    /** Ordering. */
+    LESS_OR_EQUAL(IndexType.ORDERING),
+    /** Substring. */
+    SUBSTRING(IndexType.SUBSTRING),
+    /** Approximate. */
+    APPROXIMATE(IndexType.APPROXIMATE);
+
+    private final IndexType indexType;
+
+    private IndexFilterType(IndexType indexType)
+    {
+      this.indexType = indexType;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString()
+    {
+      return indexType.toString();
+    }
+  }
+
   /*
    * FIXME Matthew Swift: Once the matching rules have been migrated we should
-   * revisit this class. IMO the core indexes (equality, etc) should all be
-   * treated in the same way as extensible indexes. In other words, there should
-   * be one table mapping index ID to index and one IndexQueryFactory. Matching
-   * rules should then be able to select which indexes they need to use when
-   * evaluating searches, and all index queries should be processed using the
-   * IndexQueryFactory implementation. Moreover, all of the evaluateXXX methods
-   * should go (the Matcher class in the SDK could implement the logic, I hope).
-   * That's the theory at least...
+   * revisit this class. All of the evaluateXXX methods should go (the Matcher
+   * class in the SDK could implement the logic, I hope).
    */
 
   /**
@@ -142,41 +167,17 @@
     final int indexEntryLimit = indexConfig.getIndexEntryLimit();
     final JEIndexConfig config = new JEIndexConfig(indexConfig.getSubstringLength());
 
-    if (indexConfig.getIndexType().contains(IndexType.EQUALITY))
-    {
-      Index equalityIndex = buildExtIndex(name, attrType, indexEntryLimit,
-          attrType.getEqualityMatchingRule(), new EqualityIndexer(attrType));
-      nameToIndexes.put(IndexType.EQUALITY.toString(), equalityIndex);
-    }
-
     if (indexConfig.getIndexType().contains(IndexType.PRESENCE))
     {
-      Index presenceIndex = newIndex(name + "." + IndexType.PRESENCE.toString(),
-          indexEntryLimit, new PresenceIndexer(attrType));
-      nameToIndexes.put(IndexType.PRESENCE.toString(), presenceIndex);
+      String indexID = IndexType.PRESENCE.toString();
+      String indexName = name + "." + indexID;
+      Index presenceIndex = newIndex(indexName, indexEntryLimit, new PresenceIndexer(attrType));
+      nameToIndexes.put(indexID, presenceIndex);
     }
-
-    if (indexConfig.getIndexType().contains(IndexType.SUBSTRING))
-    {
-      Index substringIndex = buildExtIndex(name, attrType, indexEntryLimit,
-          attrType.getSubstringMatchingRule(), new SubstringIndexer(attrType));
-      nameToIndexes.put(IndexType.SUBSTRING.toString(), substringIndex);
-    }
-
-    if (indexConfig.getIndexType().contains(IndexType.ORDERING))
-    {
-      Index orderingIndex = buildExtIndex(name, attrType, indexEntryLimit,
-          attrType.getOrderingMatchingRule(), new OrderingIndexer(attrType));
-      nameToIndexes.put(IndexType.ORDERING.toString(), orderingIndex);
-    }
-
-    if (indexConfig.getIndexType().contains(IndexType.APPROXIMATE))
-    {
-      Index approximateIndex = buildExtIndex(name, attrType, indexEntryLimit,
-          attrType.getApproximateMatchingRule(), new ApproximateIndexer(attrType));
-      nameToIndexes.put(IndexType.APPROXIMATE.toString(), approximateIndex);
-    }
-
+    buildIndexes(indexConfig, attrType, name, IndexType.EQUALITY);
+    buildIndexes(indexConfig, attrType, name, IndexType.SUBSTRING);
+    buildIndexes(indexConfig, attrType, name, IndexType.ORDERING);
+    buildIndexes(indexConfig, attrType, name, IndexType.APPROXIMATE);
 
     if (indexConfig.getIndexType().contains(IndexType.EXTENSIBLE))
     {
@@ -205,8 +206,7 @@
           if (!nameToIndexes.containsKey(indexId))
           {
             //There is no index available for this index id. Create a new index.
-            final String indexName = name + "." + indexId;
-            final Index extIndex = newExtensibleIndex(indexName, attrType, indexEntryLimit, indexer);
+            final Index extIndex = newExtensibleIndex(attrType, name, indexEntryLimit, indexer);
             nameToIndexes.put(indexId, extIndex);
           }
         }
@@ -219,28 +219,52 @@
 
   private Index newIndex(String indexName, int indexEntryLimit, Indexer indexer)
   {
-    return new Index(indexName, indexer, state, indexEntryLimit,
-        cursorEntryLimit, false, env, entryContainer);
+    return new Index(indexName, indexer, state, indexEntryLimit, cursorEntryLimit, false, env, entryContainer);
   }
 
-  private Index buildExtIndex(String name, AttributeType attrType,
-      int indexEntryLimit, MatchingRule rule, org.forgerock.opendj.ldap.spi.Indexer extIndexer) throws ConfigException
+  private void buildIndexes(LocalDBIndexCfg cfg, AttributeType attrType, String name, IndexType indexType)
+      throws ConfigException
   {
-    if (rule == null)
+    if (cfg.getIndexType().contains(indexType))
     {
-      throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(
-          attrType, extIndexer.getIndexID()));
-    }
+      final String indexID = indexType.toString();
+      final MatchingRule rule = getMatchingRule(indexType, attrType);
+      if (rule == null)
+      {
+        throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexID));
+      }
 
-    final String indexName = name + "." + extIndexer.getIndexID();
-    return newExtensibleIndex(indexName, attrType, indexEntryLimit, extIndexer);
+      for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers())
+      {
+        final Index index = newExtensibleIndex(attrType, name, cfg.getIndexEntryLimit(), indexer);
+        nameToIndexes.put(indexID, index);
+      }
+    }
   }
 
-  private Index newExtensibleIndex(String indexName, AttributeType attrType,
-      int indexEntryLimit, org.forgerock.opendj.ldap.spi.Indexer extIndexer)
+  private MatchingRule getMatchingRule(IndexType indexType, AttributeType attrType)
   {
-    JEExtensibleIndexer indexer = new JEExtensibleIndexer(attrType, extIndexer);
-    return newIndex(indexName, indexEntryLimit, indexer);
+    switch (indexType)
+    {
+    case APPROXIMATE:
+      return attrType.getApproximateMatchingRule();
+    case EQUALITY:
+      return attrType.getEqualityMatchingRule();
+    case ORDERING:
+      return attrType.getOrderingMatchingRule();
+    case SUBSTRING:
+      return attrType.getSubstringMatchingRule();
+    default:
+      throw new IllegalArgumentException("Not implemented for index type " + indexType);
+    }
+  }
+
+  private Index newExtensibleIndex(AttributeType attrType, String name, final int indexEntryLimit,
+      org.forgerock.opendj.ldap.spi.Indexer indexer)
+  {
+    final String indexName = name + "." + indexer.getIndexID();
+    final JEExtensibleIndexer extIndexer = new JEExtensibleIndexer(attrType, indexer);
+    return newIndex(indexName, indexEntryLimit, extIndexer);
   }
 
   /**
@@ -540,138 +564,6 @@
   }
 
   /**
-   * Retrieve the entry IDs that might match an equality filter.
-   *
-   * @param equalityFilter The equality filter.
-   * @param debugBuffer If not null, a diagnostic string will be written
-   *                     which will help determine how the indexes contributed
-   *                     to this search.
-   * @param monitor The database environment monitor provider that will keep
-   *                index filter usage statistics.
-   * @return The candidate entry IDs that might contain the filter
-   *         assertion value.
-   */
-  public EntryIDSet evaluateEqualityFilter(SearchFilter equalityFilter, StringBuilder debugBuffer,
-      DatabaseEnvironmentMonitor monitor)
-  {
-    try {
-      final MatchingRule matchRule = equalityFilter.getAttributeType().getEqualityMatchingRule();
-      final IndexQuery indexQuery = matchRule.getAssertion(equalityFilter.getAssertionValue())
-          .createIndexQuery(indexQueryFactory);
-      return evaluateIndexQuery(indexQuery, "equality", equalityFilter, debugBuffer, monitor);
-    }
-    catch (DecodeException e)
-    {
-      logger.traceException(e);
-      return new EntryIDSet();
-    }
-  }
-
-  /**
-   * Retrieve the entry IDs that might match a presence filter.
-   *
-   * @param filter The presence filter.
-   * @param debugBuffer If not null, a diagnostic string will be written
-   *                     which will help determine how the indexes contributed
-   *                     to this search.
-   * @param monitor The database environment monitor provider that will keep
-   *                index filter usage statistics.
-   * @return The candidate entry IDs that might contain one or more
-   *         values of the attribute type in the filter.
-   */
-  public EntryIDSet evaluatePresenceFilter(SearchFilter filter, StringBuilder debugBuffer,
-      DatabaseEnvironmentMonitor monitor)
-  {
-    final IndexQuery indexQuery = indexQueryFactory.createMatchAllQuery();
-    return evaluateIndexQuery(indexQuery, "presence", filter, debugBuffer, monitor);
-  }
-
-  /**
-   * Retrieve the entry IDs that might match a greater-or-equal filter.
-   *
-   * @param filter The greater-or-equal filter.
-   * @param debugBuffer If not null, a diagnostic string will be written
-   *                     which will help determine how the indexes contributed
-   *                     to this search.
-   * @param monitor The database environment monitor provider that will keep
-   *                index filter usage statistics.
-   * @return The candidate entry IDs that might contain a value
-   *         greater than or equal to the filter assertion value.
-   */
-  public EntryIDSet evaluateGreaterOrEqualFilter(SearchFilter filter, StringBuilder debugBuffer,
-      DatabaseEnvironmentMonitor monitor)
-  {
-    return evaluateOrderingFilter(filter, true, debugBuffer, monitor);
-  }
-
-
-  /**
-   * Retrieve the entry IDs that might match a less-or-equal filter.
-   *
-   * @param filter The less-or-equal filter.
-   * @param debugBuffer If not null, a diagnostic string will be written
-   *                     which will help determine how the indexes contributed
-   *                     to this search.
-   * @param monitor The database environment monitor provider that will keep
-   *                index filter usage statistics.
-   * @return The candidate entry IDs that might contain a value
-   *         less than or equal to the filter assertion value.
-   */
-  public EntryIDSet evaluateLessOrEqualFilter(SearchFilter filter, StringBuilder debugBuffer,
-      DatabaseEnvironmentMonitor monitor)
-  {
-    return evaluateOrderingFilter(filter, false, debugBuffer, monitor);
-  }
-
-  private EntryIDSet evaluateOrderingFilter(SearchFilter filter, boolean greater, StringBuilder debugBuffer,
-      DatabaseEnvironmentMonitor monitor)
-  {
-    try {
-      final MatchingRule matchRule = filter.getAttributeType().getOrderingMatchingRule();
-      final Assertion assertion = greater ?
-          matchRule.getGreaterOrEqualAssertion(filter.getAssertionValue()) :
-          matchRule.getLessOrEqualAssertion(filter.getAssertionValue());
-      final IndexQuery indexQuery = assertion.createIndexQuery(indexQueryFactory);
-      return evaluateIndexQuery(indexQuery, "ordering", filter, debugBuffer, monitor);
-    }
-    catch (DecodeException e)
-    {
-      logger.traceException(e);
-      return new EntryIDSet();
-    }
-  }
-
-  /**
-   * Retrieve the entry IDs that might match a substring filter.
-   *
-   * @param filter The substring filter.
-   * @param debugBuffer If not null, a diagnostic string will be written
-   *                     which will help determine how the indexes contributed
-   *                     to this search.
-   * @param monitor The database environment monitor provider that will keep
-   *                index filter usage statistics.
-   * @return The candidate entry IDs that might contain a value
-   *         that matches the filter substrings.
-   */
-  public EntryIDSet evaluateSubstringFilter(SearchFilter filter,
-                                            StringBuilder debugBuffer,
-                                            DatabaseEnvironmentMonitor monitor)
-  {
-    try {
-      final MatchingRule matchRule = filter.getAttributeType().getSubstringMatchingRule();
-      final IndexQuery indexQuery = matchRule.getSubstringAssertion(
-          filter.getSubInitialElement(), filter.getSubAnyElements(), filter.getSubFinalElement())
-          .createIndexQuery(indexQueryFactory);
-      return evaluateIndexQuery(indexQuery, "substring", filter, debugBuffer, monitor);
-    }
-    catch (DecodeException e)
-    {
-      logger.traceException(e);
-      return new EntryIDSet();
-    }
-  }
-
-  /**
    * Retrieve the entry IDs that might match two filters that restrict a value
    * to both a lower bound and an upper bound.
    *
@@ -695,20 +587,91 @@
   {
     // TODO : this implementation is not optimal
     // as it implies two separate evaluations instead of a single one,
-    // thus defeating the purpose of the optimisation done
+    // thus defeating the purpose of the optimization done
     // in IndexFilter#evaluateLogicalAndFilter method.
     // One solution could be to implement a boundedRangeAssertion that combine
     // the two operations in one.
-    EntryIDSet results = filter1.getFilterType() == FilterType.LESS_OR_EQUAL ?
-        evaluateLessOrEqualFilter(filter1, debugBuffer, monitor) :
-        evaluateGreaterOrEqualFilter(filter1, debugBuffer, monitor);
-    EntryIDSet results2 = filter2.getFilterType() == FilterType.LESS_OR_EQUAL ?
-        evaluateLessOrEqualFilter(filter2, debugBuffer, monitor) :
-        evaluateGreaterOrEqualFilter(filter2, debugBuffer, monitor);
+    EntryIDSet results = evaluate(filter1, debugBuffer, monitor);
+    EntryIDSet results2 = evaluate(filter2, debugBuffer, monitor);
     results.retainAll(results2);
     return results;
   }
 
+  private EntryIDSet evaluate(SearchFilter filter, StringBuilder debugBuffer, DatabaseEnvironmentMonitor monitor)
+  {
+    boolean isLessOrEqual = filter.getFilterType() == FilterType.LESS_OR_EQUAL;
+    IndexFilterType indexFilterType = isLessOrEqual ? IndexFilterType.LESS_OR_EQUAL : IndexFilterType.GREATER_OR_EQUAL;
+    return evaluateFilter(indexFilterType, filter, debugBuffer, monitor);
+  }
+
+  /**
+   * Retrieve the entry IDs that might match a filter.
+   *
+   * @param indexFilterType the index type filter
+   * @param filter The filter.
+   * @param debugBuffer If not null, a diagnostic string will be written
+   *                     which will help determine how the indexes contributed
+   *                     to this search.
+   * @param monitor The database environment monitor provider that will keep
+   *                index filter usage statistics.
+   * @return The candidate entry IDs that might contain a value
+   *         that matches the filter type.
+   */
+  public EntryIDSet evaluateFilter(IndexFilterType indexFilterType, SearchFilter filter, StringBuilder debugBuffer,
+      DatabaseEnvironmentMonitor monitor)
+  {
+    try
+    {
+      final IndexQuery indexQuery = getIndexQuery(indexFilterType, filter);
+      return evaluateIndexQuery(indexQuery, indexFilterType.toString(), filter, debugBuffer, monitor);
+    }
+    catch (DecodeException e)
+    {
+      logger.traceException(e);
+      return new EntryIDSet();
+    }
+  }
+
+  private IndexQuery getIndexQuery(IndexFilterType indexFilterType, SearchFilter filter) throws DecodeException
+  {
+    MatchingRule rule;
+    Assertion assertion;
+    switch (indexFilterType)
+    {
+    case EQUALITY:
+      rule = filter.getAttributeType().getEqualityMatchingRule();
+      assertion = rule.getAssertion(filter.getAssertionValue());
+      return assertion.createIndexQuery(indexQueryFactory);
+
+    case PRESENCE:
+      return indexQueryFactory.createMatchAllQuery();
+
+    case GREATER_OR_EQUAL:
+      rule = filter.getAttributeType().getOrderingMatchingRule();
+      assertion = rule.getGreaterOrEqualAssertion(filter.getAssertionValue());
+      return assertion.createIndexQuery(indexQueryFactory);
+
+    case LESS_OR_EQUAL:
+      rule = filter.getAttributeType().getOrderingMatchingRule();
+      assertion = rule.getLessOrEqualAssertion(filter.getAssertionValue());
+      return assertion.createIndexQuery(indexQueryFactory);
+
+    case SUBSTRING:
+      rule = filter.getAttributeType().getSubstringMatchingRule();
+      assertion = rule.getSubstringAssertion(
+          filter.getSubInitialElement(), filter.getSubAnyElements(), filter.getSubFinalElement());
+      return assertion.createIndexQuery(indexQueryFactory);
+
+    case APPROXIMATE:
+      rule = filter.getAttributeType().getApproximateMatchingRule();
+      assertion = rule.getAssertion(filter.getAssertionValue());
+      return assertion.createIndexQuery(indexQueryFactory);
+
+    default:
+      return null;
+    }
+  }
+
   /**
    * The default lexicographic byte array comparator.
    * Is there one available in the Java platform?
@@ -804,34 +767,6 @@
   }
 
   /**
-   * Retrieve the entry IDs that might match an approximate filter.
-   *
-   * @param approximateFilter The approximate filter.
-   * @param debugBuffer If not null, a diagnostic string will be written
-   *                     which will help determine how the indexes contributed
-   *                     to this search.
-   * @param monitor The database environment monitor provider that will keep
-   *                index filter usage statistics.
-   * @return The candidate entry IDs that might contain the filter
-   *         assertion value.
-   */
-  public EntryIDSet evaluateApproximateFilter(SearchFilter approximateFilter, StringBuilder debugBuffer,
-      DatabaseEnvironmentMonitor monitor)
-  {
-    try {
-      MatchingRule matchRule = approximateFilter.getAttributeType().getApproximateMatchingRule();
-      IndexQuery indexQuery = matchRule.getAssertion(approximateFilter.getAssertionValue())
-          .createIndexQuery(indexQueryFactory);
-      return evaluateIndexQuery(indexQuery, "approximate", approximateFilter, debugBuffer, monitor);
-    }
-    catch (DecodeException e)
-    {
-      logger.traceException(e);
-      return new EntryIDSet();
-    }
-  }
-
-  /**
    * Close cursors related to the attribute indexes.
    *
    * @throws DatabaseException If a database error occurs.
@@ -884,36 +819,15 @@
   public synchronized boolean isConfigurationChangeAcceptable(
       LocalDBIndexCfg cfg, List<LocalizableMessage> unacceptableReasons)
   {
-    AttributeType attrType = cfg.getAttribute();
+    if (!isIndexAcceptable(cfg, IndexType.EQUALITY, unacceptableReasons)
+        || !isIndexAcceptable(cfg, IndexType.SUBSTRING, unacceptableReasons)
+        || !isIndexAcceptable(cfg, IndexType.ORDERING, unacceptableReasons)
+        || !isIndexAcceptable(cfg, IndexType.APPROXIMATE, unacceptableReasons))
+    {
+      return false;
+    }
 
-    if (cfg.getIndexType().contains(IndexType.EQUALITY)
-        && nameToIndexes.get(IndexType.EQUALITY.toString()) == null
-        && attrType.getEqualityMatchingRule() == null)
-    {
-      unacceptableReasons.add(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "equality"));
-      return false;
-    }
-    if (cfg.getIndexType().contains(IndexType.SUBSTRING)
-        && nameToIndexes.get(IndexType.SUBSTRING.toString()) == null
-        && attrType.getSubstringMatchingRule() == null)
-    {
-      unacceptableReasons.add(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "substring"));
-      return false;
-    }
-    if (cfg.getIndexType().contains(IndexType.ORDERING)
-        && nameToIndexes.get(IndexType.ORDERING.toString()) == null
-        && attrType.getOrderingMatchingRule() == null)
-    {
-      unacceptableReasons.add(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "ordering"));
-      return false;
-    }
-    if (cfg.getIndexType().contains(IndexType.APPROXIMATE)
-        && nameToIndexes.get(IndexType.APPROXIMATE.toString()) == null
-        && attrType.getApproximateMatchingRule() == null)
-    {
-      unacceptableReasons.add(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "approximate"));
-      return false;
-    }
+    AttributeType attrType = cfg.getAttribute();
     if (cfg.getIndexType().contains(IndexType.EXTENSIBLE))
     {
       Set<String> newRules = cfg.getIndexExtensibleMatchingRule();
@@ -923,14 +837,27 @@
         return false;
       }
     }
+    return true;
+  }
 
+  private boolean isIndexAcceptable(LocalDBIndexCfg cfg, IndexType indexType,
+      List<LocalizableMessage> unacceptableReasons)
+  {
+    final String indexId = indexType.toString();
+    final AttributeType attrType = cfg.getAttribute();
+    if (cfg.getIndexType().contains(indexType)
+        && nameToIndexes.get(indexId) == null
+        && getMatchingRule(indexType, attrType) == null)
+    {
+      unacceptableReasons.add(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, indexId));
+      return false;
+    }
     return true;
   }
 
   /** {@inheritDoc} */
   @Override
-  public synchronized ConfigChangeResult applyConfigurationChange(
-      LocalDBIndexCfg cfg)
+  public synchronized ConfigChangeResult applyConfigurationChange(LocalDBIndexCfg cfg)
   {
     // this method is not perf sensitive, using an AtomicBoolean will not hurt
     AtomicBoolean adminActionRequired = new AtomicBoolean(false);
@@ -939,91 +866,13 @@
     {
       AttributeType attrType = cfg.getAttribute();
       String name = entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID();
-      final int indexEntryLimit = cfg.getIndexEntryLimit();
 
-      Index presenceIndex = nameToIndexes.get(IndexType.PRESENCE.toString());
-      if (cfg.getIndexType().contains(IndexType.PRESENCE))
-      {
-        if (presenceIndex == null)
-        {
-          Indexer presenceIndexer = new PresenceIndexer(attrType);
-          presenceIndex = newIndex(name + ".presence", indexEntryLimit, presenceIndexer);
-          openIndex(presenceIndex, adminActionRequired, messages);
-          nameToIndexes.put(IndexType.PRESENCE.toString(), presenceIndex);
-        }
-        else
-        {
-          // already exists. Just update index entry limit.
-          if (presenceIndex.setIndexEntryLimit(indexEntryLimit))
-          {
-            adminActionRequired.set(true);
-            messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(presenceIndex.getName()));
-          }
-        }
-      }
-      else
-      {
-        removeIndex(presenceIndex, IndexType.PRESENCE);
-      }
-
-      applyChangeToIndex(cfg, attrType, name, IndexType.EQUALITY,
-          new EqualityIndexer(attrType), adminActionRequired, messages);
-      applyChangeToIndex(cfg, attrType, name, IndexType.SUBSTRING,
-          new SubstringIndexer(attrType), adminActionRequired, messages);
-      applyChangeToIndex(cfg, attrType, name, IndexType.ORDERING,
-          new OrderingIndexer(attrType), adminActionRequired, messages);
-      applyChangeToIndex(cfg, attrType, name, IndexType.APPROXIMATE,
-          new ApproximateIndexer(attrType), adminActionRequired, messages);
-
-      if (cfg.getIndexType().contains(IndexType.EXTENSIBLE))
-      {
-        final Set<String> extensibleRules = cfg.getIndexExtensibleMatchingRule();
-        final Set<MatchingRule> validRules = new HashSet<MatchingRule>();
-        final Set<String> validIndexIds = new HashSet<String>();
-
-        for (String ruleName: extensibleRules)
-        {
-          MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName));
-          if (rule == null)
-          {
-            logger.error(ERR_CONFIG_INDEX_TYPE_NEEDS_VALID_MATCHING_RULE, attrType, ruleName);
-            continue;
-          }
-          validRules.add(rule);
-          for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers())
-          {
-            String indexId = indexer.getIndexID();
-            validIndexIds.add(indexId);
-            if (!nameToIndexes.containsKey(indexId))
-            {
-              String indexName =  name + "." + indexId;
-              Index extIndex = newExtensibleIndex(indexName, attrType, indexEntryLimit, indexer);
-              nameToIndexes.put(indexId, extIndex);
-              openIndex(extIndex, adminActionRequired, messages);
-            }
-            else
-            {
-              Index extensibleIndex = nameToIndexes.get(indexId);
-              if (extensibleIndex.setIndexEntryLimit(indexEntryLimit))
-              {
-                adminActionRequired.set(true);
-                messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(extensibleIndex.getName()));
-              }
-              if (indexConfig.getSubstringLength() != cfg.getSubstringLength())
-              {
-                extensibleIndex.setIndexer(new JEExtensibleIndexer(attrType, indexer));
-              }
-            }
-          }
-        }
-        removeIndexesForExtensibleMatchingRules(validRules, validIndexIds);
-      }
-      else
-      {
-        final Set<MatchingRule> validRules = Collections.emptySet();
-        final Set<String> validIndexIds = Collections.emptySet();
-        removeIndexesForExtensibleMatchingRules(validRules, validIndexIds);
-      }
+      applyChangeToPresenceIndex(cfg, attrType, name, adminActionRequired, messages);
+      applyChangeToIndex(cfg, attrType, name, IndexType.EQUALITY, adminActionRequired, messages);
+      applyChangeToIndex(cfg, attrType, name, IndexType.SUBSTRING, adminActionRequired, messages);
+      applyChangeToIndex(cfg, attrType, name, IndexType.ORDERING, adminActionRequired, messages);
+      applyChangeToIndex(cfg, attrType, name, IndexType.APPROXIMATE, adminActionRequired, messages);
+      applyChangeToExtensibleIndexes(cfg, attrType, name, adminActionRequired, messages);
 
       extensibleIndexesMapping = computeExtensibleIndexesMapping();
       indexConfig = cfg;
@@ -1038,6 +887,59 @@
     }
   }
 
+  private void applyChangeToExtensibleIndexes(LocalDBIndexCfg cfg, AttributeType attrType,
+      String name, AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages)
+  {
+    if (!cfg.getIndexType().contains(IndexType.EXTENSIBLE))
+    {
+      final Set<MatchingRule> validRules = Collections.emptySet();
+      final Set<String> validIndexIds = Collections.emptySet();
+      removeIndexesForExtensibleMatchingRules(validRules, validIndexIds);
+      return;
+    }
+
+    final Set<String> extensibleRules = cfg.getIndexExtensibleMatchingRule();
+    final Set<MatchingRule> validRules = new HashSet<MatchingRule>();
+    final Set<String> validIndexIds = new HashSet<String>();
+    final int indexEntryLimit = cfg.getIndexEntryLimit();
+
+    for (String ruleName : extensibleRules)
+    {
+      MatchingRule rule = DirectoryServer.getMatchingRule(toLowerCase(ruleName));
+      if (rule == null)
+      {
+        logger.error(ERR_CONFIG_INDEX_TYPE_NEEDS_VALID_MATCHING_RULE, attrType, ruleName);
+        continue;
+      }
+      validRules.add(rule);
+      for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers())
+      {
+        String indexId = indexer.getIndexID();
+        validIndexIds.add(indexId);
+        if (!nameToIndexes.containsKey(indexId))
+        {
+          Index extIndex = newExtensibleIndex(attrType, name, indexEntryLimit, indexer);
+          openIndex(extIndex, adminActionRequired, messages);
+          nameToIndexes.put(indexId, extIndex);
+        }
+        else
+        {
+          Index extensibleIndex = nameToIndexes.get(indexId);
+          if (extensibleIndex.setIndexEntryLimit(indexEntryLimit))
+          {
+            adminActionRequired.set(true);
+            messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(extensibleIndex.getName()));
+          }
+          if (indexConfig.getSubstringLength() != cfg.getSubstringLength())
+          {
+            extensibleIndex.setIndexer(new JEExtensibleIndexer(attrType, indexer));
+          }
+        }
+      }
+    }
+    removeIndexesForExtensibleMatchingRules(validRules, validIndexIds);
+  }
+
   /** Remove indexes which do not correspond to valid rules. */
   private void removeIndexesForExtensibleMatchingRules(Set<MatchingRule> validRules, Set<String> validIndexIds)
   {
@@ -1092,34 +994,67 @@
     return rules;
   }
 
-  private void applyChangeToIndex(LocalDBIndexCfg cfg, AttributeType attrType,
-      String name, IndexType indexType, org.forgerock.opendj.ldap.spi.Indexer indexer,
+  private void applyChangeToIndex(LocalDBIndexCfg cfg, AttributeType attrType, String name, IndexType indexType,
       AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages)
   {
-    final int indexEntryLimit = cfg.getIndexEntryLimit();
-
-    Index index = nameToIndexes.get(indexType.toString());
-    if (cfg.getIndexType().contains(indexType))
+    String indexId = indexType.toString();
+    Index index = nameToIndexes.get(indexId);
+    if (!cfg.getIndexType().contains(indexType))
     {
-      if (index == null)
+      removeIndex(index, indexType);
+      return;
+    }
+
+    final int indexEntryLimit = cfg.getIndexEntryLimit();
+    if (index == null)
+    {
+      final MatchingRule matchingRule = getMatchingRule(indexType, attrType);
+      for (org.forgerock.opendj.ldap.spi.Indexer indexer : matchingRule.getIndexers())
       {
-        index = openNewIndex(name, attrType, indexEntryLimit,
-            indexer, adminActionRequired, messages);
-        nameToIndexes.put(indexType.toString(), index);
-      }
-      else
-      {
-        // already exists. Just update index entry limit.
-        if(index.setIndexEntryLimit(indexEntryLimit))
-        {
-          adminActionRequired.set(true);
-          messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName()));
-        }
+        index = newExtensibleIndex(attrType, name, indexEntryLimit, indexer);
+        openIndex(index, adminActionRequired, messages);
+        nameToIndexes.put(indexId, index);
       }
     }
     else
     {
+      // already exists. Just update index entry limit.
+      if (index.setIndexEntryLimit(indexEntryLimit))
+      {
+        adminActionRequired.set(true);
+        messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName()));
+      }
+    }
+  }
+
+  private void applyChangeToPresenceIndex(LocalDBIndexCfg cfg, AttributeType attrType, String name,
+      AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages)
+  {
+    IndexType indexType = IndexType.PRESENCE;
+    String indexId = indexType.toString();
+    Index index = nameToIndexes.get(indexId);
+    if (!cfg.getIndexType().contains(indexType))
+    {
       removeIndex(index, indexType);
+      return;
+    }
+
+    final int indexEntryLimit = cfg.getIndexEntryLimit();
+    if (index == null)
+    {
+      Indexer presenceIndexer = new PresenceIndexer(attrType);
+      index = newIndex(name + ".presence", indexEntryLimit, presenceIndexer);
+      openIndex(index, adminActionRequired, messages);
+      nameToIndexes.put(indexId, index);
+    }
+    else
+    {
+      // already exists. Just update index entry limit.
+      if (index.setIndexEntryLimit(indexEntryLimit))
+      {
+        adminActionRequired.set(true);
+        messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(index.getName()));
+      }
     }
   }
 
@@ -1140,17 +1075,7 @@
     }
   }
 
-  private Index openNewIndex(String name, AttributeType attrType,
-      int indexEntryLimit, org.forgerock.opendj.ldap.spi.Indexer indexer,
-      AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages)
-  {
-    final String indexName = name + "." + indexer.getIndexID();
-    Index index = newExtensibleIndex(indexName, attrType, indexEntryLimit, indexer);
-    return openIndex(index, adminActionRequired, messages);
-  }
-
-  private Index openIndex(Index index, AtomicBoolean adminActionRequired,
-      ArrayList<LocalizableMessage> messages)
+  private void openIndex(Index index, AtomicBoolean adminActionRequired, ArrayList<LocalizableMessage> messages)
   {
     index.open();
 
@@ -1159,7 +1084,6 @@
       adminActionRequired.set(true);
       messages.add(NOTE_JEB_INDEX_ADD_REQUIRES_REBUILD.get(index.getName()));
     }
-    return index;
   }
 
   /**
@@ -1347,7 +1271,7 @@
         || matchRuleOID.equalsIgnoreCase(eqRule.getNameOrOID()))
     {
       //No matching rule is defined; use the default equality matching rule.
-      return evaluateEqualityFilter(filter, debugBuffer, monitor);
+      return evaluateFilter(IndexFilterType.EQUALITY, filter, debugBuffer, monitor);
     }
 
     MatchingRule rule = DirectoryServer.getMatchingRule(matchRuleOID);
@@ -1401,16 +1325,14 @@
 
   private boolean ruleHasAtLeasOneIndex(MatchingRule rule)
   {
-    boolean ruleHasAtLeastOneIndex = false;
     for (org.forgerock.opendj.ldap.spi.Indexer indexer : rule.getIndexers())
     {
       if (nameToIndexes.containsKey(indexer.getIndexID()))
       {
-        ruleHasAtLeastOneIndex = true;
-        break;
+        return true;
       }
     }
-    return ruleHasAtLeastOneIndex;
+    return false;
   }
 
   /**
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexFilter.java b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexFilter.java
index dd3119d..43aa8bf 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexFilter.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexFilter.java
@@ -27,6 +27,11 @@
  */
 package org.opends.server.backends.jeb;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opends.server.backends.jeb.AttributeIndex.IndexFilterType;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.monitors.DatabaseEnvironmentMonitor;
 import org.opends.server.types.AttributeType;
@@ -35,10 +40,6 @@
 
 import static org.opends.messages.JebMessages.*;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * An index filter is used to apply a search operation to a set of indexes
  * to generate a set of candidate entries.
@@ -114,7 +115,20 @@
    */
   private EntryIDSet evaluateFilter(SearchFilter filter)
   {
-    EntryIDSet candidates;
+    EntryIDSet candidates = pp(filter);
+    if (buffer != null)
+    {
+      candidates.toString(buffer);
+    }
+    return candidates;
+  }
+
+  /**
+   * @param filter
+   * @return
+   */
+  private EntryIDSet pp(SearchFilter filter)
+  {
     switch (filter.getFilterType())
     {
       case AND:
@@ -122,80 +136,49 @@
         {
           buffer.append("(&");
         }
-        candidates = evaluateLogicalAndFilter(filter);
+        final EntryIDSet res1 = evaluateLogicalAndFilter(filter);
         if (buffer != null)
         {
           buffer.append(")");
         }
-        break;
+        return res1;
 
       case OR:
         if (buffer != null)
         {
           buffer.append("(|");
         }
-        candidates = evaluateLogicalOrFilter(filter);
+        final EntryIDSet res2 = evaluateLogicalOrFilter(filter);
         if (buffer != null)
         {
           buffer.append(")");
         }
-        break;
+        return res2;
 
       case EQUALITY:
-        if (buffer != null)
-        {
-          filter.toString(buffer);
-        }
-        candidates = evaluateEqualityFilter(filter);
-        break;
+        return evaluateFilterWithDiagnostic(IndexFilterType.EQUALITY, filter);
 
       case GREATER_OR_EQUAL:
-        if (buffer != null)
-        {
-          filter.toString(buffer);
-        }
-        candidates = evaluateGreaterOrEqualFilter(filter);
-        break;
+        return evaluateFilterWithDiagnostic(IndexFilterType.GREATER_OR_EQUAL, filter);
 
       case SUBSTRING:
-        if (buffer != null)
-        {
-          filter.toString(buffer);
-        }
-        candidates = evaluateSubstringFilter(filter);
-        break;
+        return evaluateFilterWithDiagnostic(IndexFilterType.SUBSTRING, filter);
 
       case LESS_OR_EQUAL:
-        if (buffer != null)
-        {
-          filter.toString(buffer);
-        }
-        candidates = evaluateLessOrEqualFilter(filter);
-        break;
+        return evaluateFilterWithDiagnostic(IndexFilterType.LESS_OR_EQUAL, filter);
 
       case PRESENT:
-        if (buffer != null)
-        {
-          filter.toString(buffer);
-        }
-        candidates = evaluatePresenceFilter(filter);
-        break;
+        return evaluateFilterWithDiagnostic(IndexFilterType.PRESENCE, filter);
 
       case APPROXIMATE_MATCH:
-        if (buffer != null)
-        {
-          filter.toString(buffer);
-        }
-        candidates = evaluateApproximateFilter(filter);
-        break;
+        return evaluateFilterWithDiagnostic(IndexFilterType.APPROXIMATE, filter);
 
       case EXTENSIBLE_MATCH:
-         if (buffer!= null)
+        if (buffer!= null)
         {
           filter.toString(buffer);
         }
-        candidates = evaluateExtensibleFilter(filter);
-        break;
+        return evaluateExtensibleFilter(filter);
 
       case NOT:
       default:
@@ -204,15 +187,8 @@
           filter.toString(buffer);
         }
         //NYI
-        candidates = new EntryIDSet();
-        break;
+        return new EntryIDSet();
     }
-
-    if (buffer != null)
-    {
-      candidates.toString(buffer);
-    }
-    return candidates;
   }
 
   /**
@@ -266,7 +242,6 @@
     for (SearchFilter filter : fastComps)
     {
       EntryIDSet set = evaluateFilter(filter);
-
       if (retainAll(results, set))
       {
         return results;
@@ -277,7 +252,6 @@
     for (SearchFilter filter : otherComps)
     {
       EntryIDSet set = evaluateFilter(filter);
-
       if (retainAll(results, set))
       {
         return results;
@@ -292,8 +266,7 @@
     }
 
     ArrayList<SearchFilter> remainComps = new ArrayList<SearchFilter>();
-    for (Map.Entry<AttributeType, ArrayList<SearchFilter>> rangeEntry :
-         rangeComps.entrySet())
+    for (Map.Entry<AttributeType, ArrayList<SearchFilter>> rangeEntry : rangeComps.entrySet())
     {
       ArrayList<SearchFilter> rangeList = rangeEntry.getValue();
       if (rangeList.size() == 2)
@@ -359,8 +332,7 @@
     a.retainAll(b);
 
     // We may have reached the point of diminishing returns where
-    // it is quicker to stop now and process the current small number of
-    // candidates.
+    // it is quicker to stop now and process the current small number of candidates.
     return a.isDefined() && a.size() <= FILTER_CANDIDATE_THRESHOLD;
 
   }
@@ -389,179 +361,29 @@
     return EntryIDSet.unionOfSets(candidateSets, false);
   }
 
-  /**
-   * Evaluate an equality filter against the indexes.
-   *
-   * @param equalityFilter The equality filter to be evaluated.
-   * @return A set of entry IDs representing candidate entries.
-   */
-  private EntryIDSet evaluateEqualityFilter(SearchFilter equalityFilter)
+  private EntryIDSet evaluateFilterWithDiagnostic(IndexFilterType indexFilterType, SearchFilter filter)
   {
-    EntryIDSet candidates;
-    AttributeIndex attributeIndex =
-         entryContainer.getAttributeIndex(equalityFilter.getAttributeType());
-    if (attributeIndex == null)
+    if (buffer != null)
     {
-      if(monitor.isFilterUseEnabled())
-      {
-        monitor.updateStats(equalityFilter,
-            INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("equality",
-                equalityFilter.getAttributeType().getNameOrOID()));
-      }
-      candidates = new EntryIDSet();
+      filter.toString(buffer);
     }
-    else
-    {
-      candidates = attributeIndex.evaluateEqualityFilter(equalityFilter,
-          buffer, monitor);
-    }
-    return candidates;
+    return evaluateFilter(indexFilterType, filter);
   }
 
-  /**
-   * Evaluate a presence filter against the indexes.
-   *
-   * @param filter The presence filter to be evaluated.
-   * @return A set of entry IDs representing candidate entries.
-   */
-  private EntryIDSet evaluatePresenceFilter(SearchFilter filter)
+  private EntryIDSet evaluateFilter(IndexFilterType indexFilterType, SearchFilter filter)
   {
-    EntryIDSet candidates;
-    AttributeIndex attributeIndex =
-         entryContainer.getAttributeIndex(filter.getAttributeType());
-    if (attributeIndex == null)
+    AttributeIndex attributeIndex = entryContainer.getAttributeIndex(filter.getAttributeType());
+    if (attributeIndex != null)
     {
-      if(monitor.isFilterUseEnabled())
-      {
-        monitor.updateStats(filter,
-            INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("presence",
-                filter.getAttributeType().getNameOrOID()));
-      }
-      candidates = new EntryIDSet();
+      return attributeIndex.evaluateFilter(indexFilterType, filter, buffer, monitor);
     }
-    else
-    {
-      candidates = attributeIndex.evaluatePresenceFilter(filter, buffer,
-          monitor);
-    }
-    return candidates;
-  }
 
-  /**
-   * Evaluate a greater-or-equal filter against the indexes.
-   *
-   * @param filter The greater-or-equal filter to be evaluated.
-   * @return A set of entry IDs representing candidate entries.
-   */
-  private EntryIDSet evaluateGreaterOrEqualFilter(SearchFilter filter)
-  {
-    EntryIDSet candidates;
-    AttributeIndex attributeIndex =
-         entryContainer.getAttributeIndex(filter.getAttributeType());
-    if (attributeIndex == null)
+    if (monitor.isFilterUseEnabled())
     {
-      if(monitor.isFilterUseEnabled())
-      {
-        monitor.updateStats(filter,
-            INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("ordering",
-                filter.getAttributeType().getNameOrOID()));
-      }
-      candidates = new EntryIDSet();
+      monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get(
+          indexFilterType.toString(), filter.getAttributeType().getNameOrOID()));
     }
-    else
-    {
-      candidates = attributeIndex.evaluateGreaterOrEqualFilter(filter,
-          buffer, monitor);
-    }
-    return candidates;
-  }
-
-  /**
-   * Evaluate a less-or-equal filter against the indexes.
-   *
-   * @param filter The less-or-equal filter to be evaluated.
-   * @return A set of entry IDs representing candidate entries.
-   */
-  private EntryIDSet evaluateLessOrEqualFilter(SearchFilter filter)
-  {
-    EntryIDSet candidates;
-    AttributeIndex attributeIndex =
-         entryContainer.getAttributeIndex(filter.getAttributeType());
-    if (attributeIndex == null)
-    {
-      if(monitor.isFilterUseEnabled())
-      {
-        monitor.updateStats(filter,
-            INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("ordering",
-                filter.getAttributeType().getNameOrOID()));
-      }
-      candidates = new EntryIDSet();
-    }
-    else
-    {
-      candidates = attributeIndex.evaluateLessOrEqualFilter(filter, buffer,
-          monitor);
-    }
-    return candidates;
-  }
-
-  /**
-   * Evaluate a substring filter against the indexes.
-   *
-   * @param filter The substring filter to be evaluated.
-   * @return A set of entry IDs representing candidate entries.
-   */
-  private EntryIDSet evaluateSubstringFilter(SearchFilter filter)
-  {
-    EntryIDSet candidates;
-    AttributeIndex attributeIndex =
-         entryContainer.getAttributeIndex(filter.getAttributeType());
-    if (attributeIndex == null)
-    {
-      if(monitor.isFilterUseEnabled())
-      {
-        monitor.updateStats(filter,
-            INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get(
-                "substring or equality",
-                filter.getAttributeType().getNameOrOID()));
-      }
-      candidates = new EntryIDSet();
-    }
-    else
-    {
-      candidates = attributeIndex.evaluateSubstringFilter(filter,
-          buffer, monitor);
-    }
-    return candidates;
-  }
-
-  /**
-   * Evaluate an approximate filter against the indexes.
-   *
-   * @param approximateFilter The approximate filter to be evaluated.
-   * @return A set of entry IDs representing candidate entries.
-   */
-  private EntryIDSet evaluateApproximateFilter(SearchFilter approximateFilter)
-  {
-    EntryIDSet candidates;
-    AttributeIndex attributeIndex =
-         entryContainer.getAttributeIndex(approximateFilter.getAttributeType());
-    if (attributeIndex == null)
-    {
-      if(monitor.isFilterUseEnabled())
-      {
-        monitor.updateStats(approximateFilter,
-            INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("approximate",
-                approximateFilter.getAttributeType().getNameOrOID()));
-      }
-      candidates = new EntryIDSet();
-    }
-    else
-    {
-      candidates = attributeIndex.evaluateApproximateFilter(approximateFilter,
-          buffer, monitor);
-    }
-    return candidates;
+    return new EntryIDSet();
   }
 
   /**
@@ -572,29 +394,19 @@
    */
   private EntryIDSet evaluateExtensibleFilter(SearchFilter extensibleFilter)
   {
-    EntryIDSet candidates;
-
     if (extensibleFilter.getDNAttributes())
     {
       // This will always be unindexed since the filter potentially matches
       // entries containing the specified attribute type as well as any entry
       // containing the attribute in its DN as part of a superior RDN.
-      candidates = IndexQuery.createNullIndexQuery().evaluate(null);
+      return IndexQuery.createNullIndexQuery().evaluate(null);
     }
-    else
+
+    AttributeIndex attributeIndex = entryContainer.getAttributeIndex(extensibleFilter.getAttributeType());
+    if (attributeIndex != null)
     {
-      AttributeIndex attributeIndex = entryContainer
-          .getAttributeIndex(extensibleFilter.getAttributeType());
-      if (attributeIndex == null)
-      {
-        candidates = IndexQuery.createNullIndexQuery().evaluate(null);
-      }
-      else
-      {
-        candidates = attributeIndex.evaluateExtensibleFilter(extensibleFilter,
-            buffer, monitor);
-      }
+      return attributeIndex.evaluateExtensibleFilter(extensibleFilter, buffer, monitor);
     }
-    return candidates;
+    return IndexQuery.createNullIndexQuery().evaluate(null);
   }
 }
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
index 85824ee..a65e56c 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
@@ -34,6 +34,7 @@
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.schema.Schema;
 import org.forgerock.opendj.ldap.spi.IndexingOptions;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
@@ -135,7 +136,7 @@
         {
           try
           {
-            indexer.createKeys(null, value, options, keys);
+            indexer.createKeys(Schema.getDefaultSchema(), value, options, keys);
           }
           catch (DecodeException e)
           {
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
deleted file mode 100644
index 1545729..0000000
--- a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 2014 ForgeRock AS
- */
-package org.opends.server.backends.jeb;
-
-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.MatchingRule;
-import org.forgerock.opendj.ldap.schema.Schema;
-import org.forgerock.opendj.ldap.spi.Indexer;
-import org.forgerock.opendj.ldap.spi.IndexingOptions;
-import org.opends.server.types.AttributeType;
-
-/**
- * An implementation of an Indexer for attribute ordering.
- */
-public class OrderingIndexer implements Indexer
-{
-
-  /**
-   * The attribute type ordering matching rule which is also the
-   * comparator for the index keys generated by this class.
-   */
-  private final MatchingRule orderingRule;
-
-
-  /**
-   * Create a new attribute ordering indexer for the given index configuration.
-   * @param attributeType The attribute type for which an indexer is
-   * required.
-   */
-  public OrderingIndexer(AttributeType attributeType)
-  {
-    this.orderingRule = attributeType.getOrderingMatchingRule();
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public String getIndexID()
-  {
-    return "ordering";
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void createKeys(Schema schema, ByteSequence value,
-      IndexingOptions options, Collection<ByteString> keys)
-      throws DecodeException
-  {
-    keys.add(orderingRule.normalizeAttributeValue(value));
-  }
-
-}
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java b/opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
deleted file mode 100644
index 99b119d..0000000
--- a/opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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 2014 ForgeRock AS
- */
-package org.opends.server.backends.jeb;
-
-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.MatchingRule;
-import org.forgerock.opendj.ldap.schema.Schema;
-import org.forgerock.opendj.ldap.spi.Indexer;
-import org.forgerock.opendj.ldap.spi.IndexingOptions;
-import org.opends.server.types.AttributeType;
-
-/**
- * An implementation of an Indexer for attribute substrings.
- */
-public class SubstringIndexer implements Indexer
-{
-
-  private final MatchingRule substringRule;
-
-  /**
-   * Create a new attribute substring indexer for the given index configuration.
-   *
-   * @param attributeType
-   *          The attribute type for which an indexer is required.
-   */
-  public SubstringIndexer(AttributeType attributeType)
-  {
-    this.substringRule = attributeType.getSubstringMatchingRule();
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public String getIndexID()
-  {
-    return "substring";
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void createKeys(Schema schema, ByteSequence value,
-      IndexingOptions options, Collection<ByteString> keys)
-      throws DecodeException
-  { // FIXME Code similar to
-    // AbstractSubstringMatchingRuleImpl.SubstringIndexer.createKeys()
-    ByteString normValue = substringRule.normalizeAttributeValue(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));
-    }
-  }
-
-}
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
index 376aef7..dd9f962 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -26,9 +26,18 @@
  */
 package org.opends.server.backends.jeb;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
 
-import org.forgerock.opendj.ldap.*;
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ConditionResult;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.opendj.ldap.schema.MatchingRule;
 import org.forgerock.opendj.ldap.spi.IndexingOptions;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.server.AdminTestCaseUtils;
@@ -42,13 +51,17 @@
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.internal.SearchRequest;
-import org.opends.server.types.*;
 import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeBuilder;
+import org.opends.server.types.AttributeType;
 import org.opends.server.types.Attributes;
+import org.opends.server.types.Control;
 import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Entry;
 import org.opends.server.types.Modification;
 import org.opends.server.types.RDN;
+import org.opends.server.types.SearchResultEntry;
 import org.opends.server.util.Base64;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -58,6 +71,8 @@
 import com.sleepycat.je.DatabaseEntry;
 import com.sleepycat.je.LockMode;
 
+import static java.util.Collections.*;
+
 import static org.assertj.core.api.Assertions.*;
 import static org.forgerock.opendj.ldap.ConditionResult.*;
 import static org.forgerock.opendj.ldap.ModificationType.*;
@@ -636,20 +651,19 @@
 
   @Test(dependsOnMethods = "testAdd")
   public void testSearchIndex() throws Exception {
-    InternalClientConnection conn = InternalClientConnection.getRootConnection();
     Set<String> attribs = new LinkedHashSet<String>();
     String debugString;
     List<SearchResultEntry> result;
 
     // search 1
-    result = doSubtreeSearch(conn, "(&(cn=Aaccf Amar)(cn=Ardyth Bainton))", attribs);
+    result = doSubtreeSearch("(&(cn=Aaccf Amar)(cn=Ardyth Bainton))", attribs);
     assertEquals(result.size(), 0);
 
     // Adding a debug search attribute for next searches
     attribs.add(ATTR_DEBUG_SEARCH_INDEX);
 
     // search 2
-    result = doSubtreeSearch(conn, "(&(cn=Aaccf Amar)(employeeNumber=222))", attribs);
+    result = doSubtreeSearch("(&(cn=Aaccf Amar)(employeeNumber=222))", attribs);
 
     // Only one index should be used because it is below the FILTER_CANDIDATE
     debugString = getDebugString(result);
@@ -657,33 +671,32 @@
     assertResultsCountIs(1, debugString);
 
     // search 3
-    result = doSubtreeSearch(conn, "(|(cn=Aaccf Amar)(cn=Ardyth Bainton))", attribs);
+    result = doSubtreeSearch("(|(cn=Aaccf Amar)(cn=Ardyth Bainton))", attribs);
 
     debugString = getDebugString(result);
-    assertFalse(debugString.contains("NOT-INDEXED"));
+    assertThat(debugString).doesNotContain("NOT-INDEXED");
     assertResultsCountIs(2, debugString);
 
     // search 4
-    result = doSubtreeSearch(conn, "(&(employeeNumber=*)(cn=A*)(employeeNumber>=0)(employeeNumber<=z))", attribs);
+    result = doSubtreeSearch("(&(employeeNumber=*)(cn=A*)(employeeNumber>=0)(employeeNumber<=z))", attribs);
 
     debugString = getDebugString(result);
-    assertFalse(debugString.contains("NOT-INDEXED"));
+    assertThat(debugString).doesNotContain("NOT-INDEXED");
     assertResultsCountIs(12, debugString);
 
     // search 5
-    result = doSubtreeSearch(conn,
-        "(&(employeeNumber<=z)(cn<=Abbey Abbie)(cn>=0)(|(cn>=Abahri Abazari)(employeeNumber<=9)))", attribs);
-
+    result = doSubtreeSearch("(&(employeeNumber<=z)(cn<=Abbey Abbie)(cn>=0)(|(cn>=Abahri Abazari)(employeeNumber<=9)))",
+        attribs);
 
     debugString = getDebugString(result);
-    assertFalse(debugString.contains("NOT-INDEXED"));
+    assertThat(debugString).doesNotContain("NOT-INDEXED");
     assertResultsCountIs(11, debugString);
 
     // search 6
-    result = doSubtreeSearch(conn, "(cn~=Aartjan)", attribs);
+    result = doSubtreeSearch("(cn~=Aartjan)", attribs);
 
     debugString = getDebugString(result);
-    assertFalse(debugString.contains("NOT-INDEXED"));
+    assertThat(debugString).doesNotContain("NOT-INDEXED");
     assertResultsCountIs(1, debugString);
   }
 
@@ -702,12 +715,11 @@
   }
 
   /** Returns the results of subtree search on provided connection with provided filter. */
-  private List<SearchResultEntry> doSubtreeSearch(InternalClientConnection conn, String filter,
-      Set<String> attribs) throws Exception
+  private List<SearchResultEntry> doSubtreeSearch(String filter, Set<String> attribs) throws Exception
   {
     final SearchRequest request =
         newSearchRequest("dc=test,dc=com", SearchScope.WHOLE_SUBTREE, filter).addAttribute(attribs);
-    InternalSearchOperation search = conn.processSearch(request);
+    InternalSearchOperation search = getRootConnection().processSearch(request);
     return search.getSearchEntries();
   }
 
@@ -717,14 +729,10 @@
       "testNumSubordinatesIndexEntryLimitExceeded"})
   public void testDeleteSubtree() throws Exception {
     Control control = new SubtreeDeleteControl(false);
-    List<Control> deleteSubTreeControl = new ArrayList<Control>();
-    deleteSubTreeControl.add(control);
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
+    List<Control> deleteSubTreeControl = Collections.singletonList(control);
 
-    DeleteOperationBasis delete = new DeleteOperationBasis(conn,
-        InternalClientConnection.nextOperationID(),
-        InternalClientConnection.nextMessageID(),
+    DeleteOperationBasis delete = new DeleteOperationBasis(
+        getRootConnection(), nextOperationID(), nextMessageID(),
         deleteSubTreeControl,
         DN.valueOf("dc=test1,dc=com"));
 
@@ -748,9 +756,6 @@
       "testSearchScope", "testMatchedDN"})
   public void testDeleteEntry() throws Exception {
     List<Control> noControls = new ArrayList<Control>(0);
-    InternalClientConnection conn =
-        InternalClientConnection.getRootConnection();
-
     EntryContainer ec =
         backend.getRootContainer().getEntryContainer(DN.valueOf("ou=People,dc=test,dc=com"));
 
@@ -762,16 +767,11 @@
       EntryID entryID = ec.getDN2ID().get(null,
           DN.valueOf("uid=user.539,ou=People,dc=test,dc=com"), LockMode.DEFAULT);
 
-      DeleteOperationBasis delete = new DeleteOperationBasis(conn,
-        InternalClientConnection.nextOperationID(),
-        InternalClientConnection.nextMessageID(),
-        noControls,
-
+      DeleteOperationBasis delete = new DeleteOperationBasis(
+          getRootConnection(), nextOperationID(), nextMessageID(),
+          noControls,
           DN.valueOf("uid=user.539,ou=People,dc=test,dc=com"));
-
-
-      backend.deleteEntry(DN.valueOf("uid=user.539,ou=People,dc=test,dc=com"),
-          delete);
+      backend.deleteEntry(DN.valueOf("uid=user.539,ou=People,dc=test,dc=com"), delete);
 
 
       assertFalse(ec.entryExists(DN.valueOf("uid=user.539,ou=People,dc=test,dc=com")));
@@ -780,21 +780,22 @@
       assertFalse(ec.getDN2URI().delete(null,
           DN.valueOf("uid=user.539,ou=People,dc=test,dc=com")));
 
-      AttributeType attribute =
-          entries.get(0).getAttribute("cn").get(0).getAttributeType();
+      AttributeType attribute = entries.get(0).getAttribute("cn").get(0).getAttributeType();
       AttributeIndex index = ec.getAttributeIndex(attribute);
+      AttributeType attrType = index.getAttributeType();
 
-      Indexer presenceIndexer = new PresenceIndexer(index.getAttributeType());
-      assertIndexContainsID(presenceIndexer, entry, index.getPresenceIndex(), entryID, FALSE);
+      List<? extends Indexer> indexers;
+      indexers = singletonList(new PresenceIndexer(index.getAttributeType()));
+      assertIndexContainsID(indexers, entry, index.getPresenceIndex(), entryID, FALSE);
 
-      Indexer equalityIndexer = newEqualityIndexer(index);
-      assertIndexContainsID(equalityIndexer, entry, index.getEqualityIndex(), entryID, FALSE);
+      indexers = newJEExtensibleIndexers(attrType, attrType.getEqualityMatchingRule());
+      assertIndexContainsID(indexers, entry, index.getEqualityIndex(), entryID, FALSE);
 
-      Indexer substringIndexer = newSubstringIndexer(index);
-      assertIndexContainsID(substringIndexer, entry, index.getSubstringIndex(), entryID, FALSE);
+      indexers = newJEExtensibleIndexers(attrType, attrType.getSubstringMatchingRule());
+      assertIndexContainsID(indexers, entry, index.getSubstringIndex(), entryID, FALSE);
 
-      Indexer orderingIndexer = newOrderingIndexer(index);
-      assertIndexContainsID(orderingIndexer, entry, index.getOrderingIndex(), entryID, FALSE);
+      indexers = newJEExtensibleIndexers(attrType, attrType.getOrderingMatchingRule());
+      assertIndexContainsID(indexers, entry, index.getOrderingIndex(), entryID, FALSE);
     }
     finally
     {
@@ -802,30 +803,14 @@
     }
   }
 
-  private Indexer newOrderingIndexer(AttributeIndex index)
+  private List<JEExtensibleIndexer> newJEExtensibleIndexers(AttributeType attrType, MatchingRule matchingRule)
   {
-    AttributeType attrType = index.getAttributeType();
-    return new JEExtensibleIndexer(attrType, new OrderingIndexer(attrType));
-  }
-
-  private Indexer newEqualityIndexer(AttributeIndex index)
-  {
-    AttributeType attrType = index.getAttributeType();
-    return new JEExtensibleIndexer(attrType, new EqualityIndexer(attrType));
-  }
-
-  private Indexer newSubstringIndexer(AttributeIndex index)
-  {
-    AttributeType attrType = index.getAttributeType();
-    return new JEExtensibleIndexer(attrType, new SubstringIndexer(attrType));
-  }
-
-  private IndexingOptions getOptions(AttributeIndex index)
-  {
-    final IndexingOptions options = mock(IndexingOptions.class);
-    when(options.substringKeySize()).thenReturn(
-        index.getConfiguration().getSubstringLength());
-    return options;
+    List<JEExtensibleIndexer> extIndexers = new ArrayList<JEExtensibleIndexer>();
+    for (org.forgerock.opendj.ldap.spi.Indexer indexer : matchingRule.getIndexers())
+    {
+      extIndexers.add(new JEExtensibleIndexer(attrType, indexer));
+    }
+    return extIndexers;
   }
 
   private IndexingOptions getOptions()
@@ -835,27 +820,32 @@
     return options;
   }
 
-  private void assertIndexContainsID(Indexer indexer, Entry entry, Index index,
-      EntryID entryID)
+  private void assertIndexContainsID(List<? extends Indexer> indexers, Entry entry, Index index, EntryID entryID)
   {
-    Set<ByteString> addKeys = new HashSet<ByteString>();
-    indexer.indexEntry(entry, addKeys, getOptions());
-
-    DatabaseEntry key = new DatabaseEntry();
-    for (ByteString keyBytes : addKeys)
+    for (Indexer indexer : indexers)
     {
-      key.setData(keyBytes.toByteArray());
-      assertEquals(index.containsID(null, key, entryID), TRUE);
+      Set<ByteString> addKeys = new HashSet<ByteString>();
+      indexer.indexEntry(entry, addKeys, getOptions());
+
+      DatabaseEntry key = new DatabaseEntry();
+      for (ByteString keyBytes : addKeys)
+      {
+        key.setData(keyBytes.toByteArray());
+        assertEquals(index.containsID(null, key, entryID), TRUE);
+      }
     }
   }
 
-  private void assertIndexContainsID(Indexer indexer, Entry entry,
+  private void assertIndexContainsID(List<? extends Indexer> indexers, Entry entry,
       Index index, EntryID entryID, ConditionResult expected)
   {
-    Set<ByteString> addKeys = new HashSet<ByteString>();
-    indexer.indexEntry(entry, addKeys, getOptions());
+    for (Indexer indexer : indexers)
+    {
+      Set<ByteString> addKeys = new HashSet<ByteString>();
+      indexer.indexEntry(entry, addKeys, getOptions());
 
-    assertIndexContainsID(addKeys, index, entryID, expected);
+      assertIndexContainsID(addKeys, index, entryID, expected);
+    }
   }
 
   private void assertIndexContainsID(Set<ByteString> addKeys, Index index,
@@ -900,21 +890,22 @@
         assertEquals(value.toString(), "777");
       }
 
-      AttributeType attribute =
-          entry.getAttribute("cn").get(0).getAttributeType();
+      AttributeType attribute = entry.getAttribute("cn").get(0).getAttributeType();
       AttributeIndex index = ec.getAttributeIndex(attribute);
+      AttributeType attrType = index.getAttributeType();
 
-      Indexer orderingIndexer = newOrderingIndexer(index);
-      assertIndexContainsID(orderingIndexer, entry, index.getOrderingIndex(), entryID, TRUE);
-      assertIndexContainsID(orderingIndexer, oldEntry, index.getOrderingIndex(), entryID, FALSE);
+      List<? extends Indexer> indexers;
+      indexers = newJEExtensibleIndexers(attrType, attrType.getOrderingMatchingRule());
+      assertIndexContainsID(indexers, entry, index.getOrderingIndex(), entryID, TRUE);
+      assertIndexContainsID(indexers, oldEntry, index.getOrderingIndex(), entryID, FALSE);
 
-      Indexer substringIndexer = newSubstringIndexer(index);
-      assertIndexContainsID(substringIndexer, entry, index.getSubstringIndex(), entryID, TRUE);
-      assertIndexContainsID(substringIndexer, oldEntry, index.getSubstringIndex(), entryID, FALSE);
+      indexers = newJEExtensibleIndexers(attrType, attrType.getSubstringMatchingRule());
+      assertIndexContainsID(indexers, entry, index.getSubstringIndex(), entryID, TRUE);
+      assertIndexContainsID(indexers, oldEntry, index.getSubstringIndex(), entryID, FALSE);
 
-      Indexer equalityIndexer = newEqualityIndexer(index);
-      assertIndexContainsID(equalityIndexer, entry, index.getEqualityIndex(), entryID, TRUE);
-      assertIndexContainsID(equalityIndexer, oldEntry, index.getEqualityIndex(), entryID, FALSE);
+      indexers = newJEExtensibleIndexers(attrType, attrType.getEqualityMatchingRule());
+      assertIndexContainsID(indexers, entry, index.getEqualityIndex(), entryID, TRUE);
+      assertIndexContainsID(indexers, oldEntry, index.getEqualityIndex(), entryID, FALSE);
     }
     finally
     {
@@ -934,10 +925,7 @@
     AttributeIndex titleIndex;
     AttributeIndex nameIndex;
     Set<ByteString> addKeys;
-    Indexer presenceIndexer;
-    Indexer equalityIndexer;
-    Indexer substringIndexer;
-    Indexer orderingIndexer;
+    List<? extends Indexer> indexers;
 
     EntryContainer ec = backend.getRootContainer().getEntryContainer(
         DN.valueOf("dc=test,dc=com"));
@@ -996,11 +984,8 @@
       assertIndexContainsID(addKeys, nameIndex.getPresenceIndex(), entryID, TRUE);
 
       List<Control> noControls = new ArrayList<Control>(0);
-      InternalClientConnection conn = InternalClientConnection.getRootConnection();
-
-      ModifyOperationBasis modifyOp = new ModifyOperationBasis(conn, InternalClientConnection
-          .nextOperationID(), InternalClientConnection.nextMessageID(), noControls, DN
-          .valueOf("uid=user.1,ou=People,dc=test,dc=com"), modifications);
+      ModifyOperationBasis modifyOp = new ModifyOperationBasis(getRootConnection(), nextOperationID(), nextMessageID(),
+          noControls, DN.valueOf("uid=user.1,ou=People,dc=test,dc=com"), modifications);
 
       backend.replaceEntry(entry, newEntry, modifyOp);
 
@@ -1031,29 +1016,28 @@
       assertFalse(entry.getAttribute("employeenumber").contains(
           Attributes.create("employeenumber", "1")));
 
-      presenceIndexer = new PresenceIndexer(titleIndex.getAttributeType());
-      assertIndexContainsID(presenceIndexer, entry, titleIndex.getPresenceIndex(), entryID);
+      AttributeType titleIndexAttrType = titleIndex.getAttributeType();
+      AttributeType nameIndexAttrType = nameIndex.getAttributeType();
 
-      presenceIndexer = new PresenceIndexer(nameIndex.getAttributeType());
-      assertIndexContainsID(presenceIndexer, entry, nameIndex.getPresenceIndex(), entryID);
+      indexers = singletonList(new PresenceIndexer(titleIndexAttrType));
+      assertIndexContainsID(indexers, entry, titleIndex.getPresenceIndex(), entryID);
+      indexers = singletonList(new PresenceIndexer(nameIndexAttrType));
+      assertIndexContainsID(indexers, entry, nameIndex.getPresenceIndex(), entryID);
 
-      orderingIndexer = newOrderingIndexer(titleIndex);
-      assertIndexContainsID(orderingIndexer, entry, titleIndex.getOrderingIndex(), entryID);
+      indexers = newJEExtensibleIndexers(titleIndexAttrType, titleIndexAttrType.getOrderingMatchingRule());
+      assertIndexContainsID(indexers, entry, titleIndex.getOrderingIndex(), entryID);
+      indexers = newJEExtensibleIndexers(nameIndexAttrType, nameIndexAttrType.getOrderingMatchingRule());
+      assertIndexContainsID(indexers, entry, nameIndex.getOrderingIndex(), entryID);
 
-      orderingIndexer = newOrderingIndexer(nameIndex);
-      assertIndexContainsID(orderingIndexer, entry, nameIndex.getOrderingIndex(), entryID);
+      indexers = newJEExtensibleIndexers(titleIndexAttrType, titleIndexAttrType.getEqualityMatchingRule());
+      assertIndexContainsID(indexers, entry, titleIndex.getEqualityIndex(), entryID);
+      indexers = newJEExtensibleIndexers(nameIndexAttrType, nameIndexAttrType.getEqualityMatchingRule());
+      assertIndexContainsID(indexers, entry, nameIndex.getEqualityIndex(), entryID);
 
-      equalityIndexer = newEqualityIndexer(titleIndex);
-      assertIndexContainsID(equalityIndexer, entry, titleIndex.getEqualityIndex(), entryID);
-
-      equalityIndexer = newEqualityIndexer(nameIndex);
-      assertIndexContainsID(equalityIndexer, entry, nameIndex.getEqualityIndex(), entryID);
-
-      substringIndexer = newSubstringIndexer(titleIndex);
-      assertIndexContainsID(substringIndexer, entry, titleIndex.getSubstringIndex(), entryID);
-
-      substringIndexer = newSubstringIndexer(nameIndex);
-      assertIndexContainsID(substringIndexer, entry, nameIndex.getSubstringIndex(), entryID);
+      indexers = newJEExtensibleIndexers(titleIndexAttrType, titleIndexAttrType.getSubstringMatchingRule());
+      assertIndexContainsID(indexers, entry, titleIndex.getSubstringIndex(), entryID);
+      indexers = newJEExtensibleIndexers(nameIndexAttrType, nameIndexAttrType.getSubstringMatchingRule());
+      assertIndexContainsID(indexers, entry, nameIndex.getSubstringIndex(), entryID);
     }
     finally
     {
@@ -1069,21 +1053,18 @@
     ec.sharedLock.lock();
     try
     {
-      Entry entry =
-          ec.getEntry(DN.valueOf("uid=user.2,ou=People,dc=test,dc=com"));
-      entry.setDN(DN.valueOf("cn=Abbey Abbie,ou=People,dc=test,dc=com"));
+      DN user2Dn = DN.valueOf("uid=user.2,ou=People,dc=test,dc=com");
+      DN abbieDn = DN.valueOf("cn=Abbey Abbie,ou=People,dc=test,dc=com");
+      Entry entry = ec.getEntry(user2Dn);
+      entry.setDN(abbieDn);
 
+      backend.renameEntry(user2Dn, entry, null);
 
-      backend.renameEntry(DN.valueOf("uid=user.2,ou=People,dc=test,dc=com"),
-          entry, null);
+      assertNotNull(backend.getEntry(abbieDn));
+      assertNotNull(ec.getDN2ID().get(null, abbieDn, LockMode.DEFAULT));
 
-      assertNotNull(backend.getEntry(DN.valueOf("cn=Abbey Abbie,ou=People,dc=test,dc=com")));
-      assertNotNull(ec.getDN2ID().get(null, DN.valueOf("cn=Abbey Abbie,ou=People,dc=test,dc=com"), LockMode.DEFAULT));
-
-
-      assertNull(backend.getEntry(DN.valueOf("uid=user.2,ou=People,dc=test,dc=com")));
-      assertNull(ec.getDN2ID().get(null,
-          DN.valueOf("uid=user.2,ou=People,dc=test,dc=com"), LockMode.DEFAULT));
+      assertNull(backend.getEntry(user2Dn));
+      assertNull(ec.getDN2ID().get(null, user2Dn, LockMode.DEFAULT));
     }
     finally
     {
@@ -1111,12 +1092,8 @@
       assertTrue(newSuperiorID.compareTo(oldID) > 0);
 
       List<Control> noControls = new ArrayList<Control>(0);
-      InternalClientConnection conn =
-          InternalClientConnection.getRootConnection();
-
-      ModifyDNOperationBasis modifyDN = new ModifyDNOperationBasis(conn,
-          InternalClientConnection.nextOperationID(),
-          InternalClientConnection.nextMessageID(),
+      ModifyDNOperationBasis modifyDN = new ModifyDNOperationBasis(
+          getRootConnection(), nextOperationID(), nextMessageID(),
           noControls,
           DN.valueOf("ou=People,dc=test,dc=com"),
           RDN.decode("ou=Good People"),
@@ -1199,8 +1176,8 @@
     RootContainer rootContainer = backend.getRootContainer();
     EntryContainer ec = rootContainer.getEntryContainer(DN.valueOf("dc=test,dc=com"));
 
-    AttributeIndex attributeIndex =
-        ec.getAttributeIndex(DirectoryServer.getAttributeType("givenname"));
+    AttributeType givennameAttr = DirectoryServer.getAttributeType("givenname");
+    AttributeIndex attributeIndex = ec.getAttributeIndex(givennameAttr);
     assertNull(attributeIndex.getEqualityIndex());
     assertNull(attributeIndex.getPresenceIndex());
     assertNull(attributeIndex.getSubstringIndex());
@@ -1208,44 +1185,15 @@
     assertNotNull(attributeIndex.getApproximateIndex());
     List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>();
     ec.listDatabases(databases);
-    boolean eqfound = false;
-    boolean prfound = false;
-    boolean subfound = false;
-    boolean orfound = false;
-    boolean apfound = false;
-    for(DatabaseContainer dc : databases)
-    {
-      if(dc.getName().toLowerCase().contains("givenname.approximate"))
-      {
-        apfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.presence"))
-      {
-        prfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.substring"))
-      {
-        subfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.ordering"))
-      {
-        orfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.equality"))
-      {
-        eqfound = true;
-      }
-    }
-    assertFalse(eqfound);
-    assertFalse(prfound);
-    assertFalse(subfound);
-    assertFalse(orfound);
-    assertTrue(apfound);
+    assertFalse(findContainer(databases, "givenname.equality"));
+    assertFalse(findContainer(databases, "givenname.presence"));
+    assertFalse(findContainer(databases, "givenname.substring"));
+    assertFalse(findContainer(databases, "givenname.ordering"));
+    assertTrue(findContainer(databases, "givenname.approximate"));
 
     final SearchRequest request = newSearchRequest("dc=test,dc=com", SearchScope.SUBORDINATES, "(givenName~=Aaccf)")
         .addAttribute(ATTR_DEBUG_SEARCH_INDEX);
     InternalSearchOperation search = getRootConnection().processSearch(request);
-
     List<SearchResultEntry> result = search.getSearchEntries();
 
     //No indexes should be used.
@@ -1272,39 +1220,11 @@
     assertNull(attributeIndex.getApproximateIndex());
     databases = new ArrayList<DatabaseContainer>();
     ec.listDatabases(databases);
-    eqfound = false;
-    prfound = false;
-    subfound = false;
-    orfound = false;
-    apfound = false;
-    for(DatabaseContainer dc : databases)
-    {
-      if(dc.getName().toLowerCase().contains("givenname.approximate"))
-      {
-        apfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.presence"))
-      {
-        prfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.substring"))
-      {
-        subfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.ordering"))
-      {
-        orfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.equality"))
-      {
-        eqfound = true;
-      }
-    }
-    assertTrue(eqfound);
-    assertTrue(prfound);
-    assertTrue(subfound);
-    assertTrue(orfound);
-    assertFalse(apfound);
+    assertTrue(findContainer(databases, "givenname.equality"));
+    assertTrue(findContainer(databases, "givenname.presence"));
+    assertTrue(findContainer(databases, "givenname.substring"));
+    assertTrue(findContainer(databases, "givenname.ordering"));
+    assertFalse(findContainer(databases, "givenname.approximate"));
 
     // Delete the entries attribute index.
     resultCode = TestCaseUtils.applyModifications(true,
@@ -1314,8 +1234,7 @@
 
     assertEquals(resultCode, 0);
 
-    assertNull(ec.getAttributeIndex(
-        DirectoryServer.getAttributeType("givenname")));
+    assertNull(ec.getAttributeIndex(givennameAttr));
     databases = new ArrayList<DatabaseContainer>();
     ec.listDatabases(databases);
     for(DatabaseContainer dc : databases)
@@ -1338,43 +1257,14 @@
 
     assertEquals(resultCode, 0);
 
-    assertNotNull(ec.getAttributeIndex(
-        DirectoryServer.getAttributeType("givenname")));
+    assertNotNull(ec.getAttributeIndex(givennameAttr));
     databases = new ArrayList<DatabaseContainer>();
     ec.listDatabases(databases);
-    eqfound = false;
-    prfound = false;
-    subfound = false;
-    orfound = false;
-    apfound = false;
-    for(DatabaseContainer dc : databases)
-    {
-      if(dc.getName().toLowerCase().contains("givenname.approximate"))
-      {
-        apfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.presence"))
-      {
-        prfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.substring"))
-      {
-        subfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.ordering"))
-      {
-        orfound = true;
-      }
-      if(dc.getName().toLowerCase().contains("givenname.equality"))
-      {
-        eqfound = true;
-      }
-    }
-    assertTrue(eqfound);
-    assertTrue(prfound);
-    assertTrue(subfound);
-    assertTrue(orfound);
-    assertFalse(apfound);
+    assertTrue(findContainer(databases, "givenname.equality"));
+    assertTrue(findContainer(databases, "givenname.presence"));
+    assertTrue(findContainer(databases, "givenname.substring"));
+    assertTrue(findContainer(databases, "givenname.ordering"));
+    assertFalse(findContainer(databases, "givenname.approximate"));
 
     // Make sure changing the index entry limit on an index where the limit
     // is already exceeded causes warnings.
@@ -1398,6 +1288,18 @@
     assertEquals(resultCode, 0);
   }
 
+  private boolean findContainer(List<DatabaseContainer> databases, String lowercaseName)
+  {
+    for (DatabaseContainer dc : databases)
+    {
+      if (dc.getName().toLowerCase().contains(lowercaseName))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
   @Test(dependsOnMethods = {"testDeleteEntry", "testSearchScope",
       "testSearchIndex", "testMatchedDN"})
   public void testSearchNotIndexed() throws Exception {
@@ -1486,14 +1388,11 @@
     ResultCode expectedResultCode
     ) throws Exception
   {
-    InternalClientConnection conn = getRootConnection();
-    SearchFilter filter = SearchFilter.objectClassPresent();
-
     // Test is performed with each and every scope
     for (SearchScope scope: SearchScope.values())
     {
-      final SearchRequest request = newSearchRequest(searchBaseDN, scope, filter);
-      InternalSearchOperation searchOperation = conn.processSearch(request);
+      final SearchRequest request = newSearchRequest(searchBaseDN, scope);
+      InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
 
       assertEquals(searchOperation.getResultCode(), expectedResultCode);
       assertEquals(searchOperation.getMatchedDN(), expectedMatchedDN);

--
Gitblit v1.10.0