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

Jean-Noel Rouvignac
10.09.2014 89485d11a14d27f7b0578695d436335de8bc58bd
OPENDJ-1591 (CR-5206) Switch to SDK matching rules

After r11260 some code cleanup can be performed.

ApproximateIndexer.java, EqualityIndexer.java, OrderingIndexer.java, SubstringIndexer.java: REMOVED
Replaced with calling MatchingRule.getIndexers().

AttributeIndex.java:
Consequence of removing the indexer types.
Changed buildExtIndex() into buildIndexes() + getMatchingRule().
Factorized code by extracting IndexFilterType enum: Inlined several evaluate*Filter() methods and replaced them with the newly extracted methods evaluateFilter() + getIndexQuery().
Simplified evaluateBoundedRange() with the help of the newly extracted methods evaluateFilter() + getIndexQuery().
Extracted method isIndexAcceptable().
Changed buildExtIndex() into buildIndexes().
Extracted methods applyChangeToPresenceIndex() and applyChangeToExtensibleIndexes() from applyConfigurationChange().
In applyChangeToIndex(), reworked the code.
Removed openNewIndex().

IndexFilter.java:
Consequence of the changes to AttributeIndex.evaluate*Filter().
Removed several evaluate*Filter() methods and replaced them with a single extracted evaluateFilter() method.

TestBackendImpl.java:
Consequence of removing the indexer types.
3 files deleted
4 files modified
1616 ■■■■■ changed files
opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java 78 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java 672 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexFilter.java 292 ●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java 3 ●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java 79 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java 89 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java 403 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
File was deleted
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;
  }
  /**
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);
  }
}
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)
          {
opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
File was deleted
opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
File was deleted
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);