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

Jean-Noel Rouvignac
07.25.2014 4609647b9acd61e11ce2b2c65c88efbc9e601489
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleIndexer.java
@@ -22,18 +22,23 @@
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Portions Copyright 2014 ForgeRock AS
 */
package org.opends.server.api;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.ldap.spi.Indexer;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import org.opends.server.types.AttributeValue;
/**
 * This class is registered with a Backend and it provides call- backs
 * for indexing attribute values. An index implementation will use
@@ -44,19 +49,8 @@
    mayInstantiate = false,
    mayExtend = true,
    mayInvoke = false)
public abstract class ExtensibleIndexer
public abstract class ExtensibleIndexer implements Indexer
{
  /**
   * Returns the index name preferred by this indexer. This name
   * appended with the identifier returned from
   * {@link #getExtensibleIndexID()} will be used as the index
   * database name.
   *
   * @return The name of the index for this indexer.
   */
  public abstract String getPreferredIndexName();
  /**
   * Returns an index identifier associated with this indexer. An
@@ -81,27 +75,67 @@
   * @param keys
   *          The set into which the generated keys will be inserted.
   */
  public abstract void getKeys(AttributeValue value,
      Set<byte[]> keys);
  public abstract void getKeys(AttributeValue value, Set<byte[]> keys);
  /** {@inheritDoc} */
  @Override
  public void createKeys(Schema schema, ByteSequence value,
      IndexingOptions options, Collection<ByteString> keys)
      throws DecodeException
  {
    throw new RuntimeException("Not implemented yet");
  }
  /**
   * Generates a map of index keys and a boolean flag indicating
   * whether the corresponding key will be inserted or deleted.
   *
   * @param value
   * @param attrValue
   *          The attribute for which keys are required.
   * @param modifiedKeys
   *          A map containing the keys and a boolean. Keys
   *          corresponding to the boolean value <code>true
   *              </code>
   *          corresponding to the boolean value <code>true</code>
   *          should be inserted and <code>false</code> should be
   *          deleted.
   * @param insert
   *          <code>true</code> if generated keys should be inserted
   *          or <code>false</code> otherwise.
   */
  public abstract void getKeys(AttributeValue value,
      Map<byte[], Boolean> modifiedKeys, Boolean insert);
  public void getKeys(AttributeValue attrValue, Map<byte[], Boolean> modifiedKeys, Boolean insert)
  {
    final Set<byte[]> keys = new HashSet<byte[]>();
    getKeys(attrValue, keys);
    computeModifiedKeys(modifiedKeys, insert, keys);
  }
  /**
   * Computes the modified keys by an indexer.
   *
   * @param modifiedKeys
   *          A map containing the keys and a boolean. Keys
   *          corresponding to the boolean value <code>true</code>
   *          should be inserted and <code>false</code> should be
   *          deleted.
   * @param insert
   *          <code>true</code> if generated keys should be inserted
   *          or <code>false</code> otherwise.
   * @param keys
   *          the newly generated keys that will be added or removed from the Map
   */
  public static void computeModifiedKeys(Map<byte[], Boolean> modifiedKeys,
      Boolean insert, final Set<byte[]> keys)
  {
    for (byte[] key : keys)
    {
      Boolean cInsert = modifiedKeys.get(key);
      if (cInsert == null)
      {
        modifiedKeys.put(key, insert);
      }
      else if (!cInsert.equals(insert))
      {
        modifiedKeys.remove(key);
      }
    }
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleMatchingRule.java
@@ -26,15 +26,12 @@
 */
package org.opends.server.api;
import java.util.Collection;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.DecodeException;
import org.opends.server.types.IndexConfig;
import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
/**
 * This interface defines the set of methods that must be
@@ -49,17 +46,15 @@
public interface ExtensibleMatchingRule extends MatchingRule
{
  /**
   * Returns a collection of extensible indexers associated with this
   * matching rule.
   * Returns a collection of extensible indexers associated with this matching
   * rule.
   *
   * @param config
   *          The index configuration to be used by this matching
   *          rule.
   * @return The collection of extensible indexers associated with
   *         this matching rule.
   * @param indexingOptions
   *          The indexing options to be used by this matching rule.
   * @return The collection of extensible indexers associated with this matching
   *         rule.
   */
  Collection<ExtensibleIndexer> getIndexers(
      IndexConfig config);
  Collection<ExtensibleIndexer> getIndexers(IndexingOptions indexingOptions);
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/IndexQueryFactory.java
File was deleted
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
@@ -27,6 +27,7 @@
package org.opends.server.backends.jeb;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -34,6 +35,7 @@
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.DecodeException;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.ExtensibleIndexer;
import org.opends.server.types.*;
/**
@@ -165,24 +167,28 @@
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
      for (AttributeValue value : attr)
      {
        try
        for (AttributeValue value : attr)
        {
          byte[] keyBytes =
               approximateRule.normalizeAttributeValue(value.getValue()).toByteArray();
          getKeys(value, keys);
        }
      }
    }
  }
          keys.add(keyBytes);
        }
        catch (DecodeException e)
        {
          logger.traceException(e);
        }
      }
  private void getKeys(AttributeValue value, Set<byte[]> keys)
  {
    try
    {
      byte[] keyBytes =
           approximateRule.normalizeAttributeValue(value.getValue()).toByteArray();
      keys.add(keyBytes);
    }
    catch (DecodeException e)
    {
      logger.traceException(e);
    }
  }
@@ -202,32 +208,21 @@
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
      for (AttributeValue value : attr)
      {
        try
        for (AttributeValue value : attr)
        {
          byte[] keyBytes = approximateRule
              .normalizeAttributeValue(value.getValue()).toByteArray();
          Boolean cInsert = modifiedKeys.get(keyBytes);
          if(cInsert == null)
          {
            modifiedKeys.put(keyBytes, insert);
          }
          else if(!cInsert.equals(insert))
          {
            modifiedKeys.remove(keyBytes);
          }
        }
        catch (DecodeException e)
        {
          logger.traceException(e);
          getKeys(value, modifiedKeys, insert);
        }
      }
    }
  }
  private void getKeys(AttributeValue value, Map<byte[], Boolean> modifiedKeys,
      Boolean insert)
  {
    Set<byte[]> keys = new HashSet<byte[]>();
    getKeys(value, keys);
    ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys);
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
@@ -33,6 +33,8 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn;
import org.opends.server.admin.std.server.LocalDBIndexCfg;
@@ -144,6 +146,7 @@
    String name =
        entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID();
    int indexEntryLimit = indexConfig.getIndexEntryLimit();
    JEIndexConfig config = new JEIndexConfig(indexConfig.getSubstringLength());
    if (indexConfig.getIndexType().contains(
            LocalDBIndexCfgDefn.IndexType.EQUALITY))
@@ -186,8 +189,7 @@
        throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "substring"));
      }
      Indexer substringIndexer = new SubstringIndexer(attrType,
                                         indexConfig.getSubstringLength());
      Indexer substringIndexer = new SubstringIndexer(attrType, config);
      this.substringIndex = new Index(name + ".substring",
                                     substringIndexer,
                                     state,
@@ -248,7 +250,6 @@
      //Collation equality and Ordering matching rules share the same
      //indexer and index. A Collation substring matching rule is treated
      // differently as it uses a separate indexer and index.
      IndexConfig config = new JEIndexConfig(indexConfig.getSubstringLength());
      for(String ruleName:extensibleRules)
      {
        ExtensibleMatchingRule rule =
@@ -262,11 +263,7 @@
        Map<String,Index> indexMap = new HashMap<String,Index>();
        for(ExtensibleIndexer indexer : rule.getIndexers(config))
        {
          String indexerId = indexer.getExtensibleIndexID();
          String indexID =
                  attrType.getNameOrOID()  + "."
                    + indexer.getPreferredIndexName()
                    + "." + indexerId;
          String indexID = attrType.getNameOrOID() + "." + indexer.getIndexID();
          if(!extensibleIndexes.isIndexPresent(indexID))
          {
            //There is no index available for this index id. Create a new index.
@@ -290,9 +287,9 @@
        indexMap.put(indexer.getExtensibleIndexID(),
                extensibleIndexes.getIndex(indexID));
      }
      IndexQueryFactory<IndexQuery> factory =
              new IndexQueryFactoryImpl(indexMap);
      extensibleIndexes.addQueryFactory(rule, factory);
        IndexQueryFactory<IndexQuery> factory =
            new IndexQueryFactoryImpl(indexMap, config);
        extensibleIndexes.addQueryFactory(rule, factory);
      }
    }
  }
@@ -739,6 +736,9 @@
   */
  Set<ByteString> substringKeys(byte[] value)
  {
    // FIXME replace this code with SDK's
    // AbstractSubstringMatchingRuleImpl.SubstringIndexer.createKeys()
    // Eliminate duplicates by putting the keys into a set.
    // Sorting the keys will ensure database record locks are acquired
    // in a consistent order and help prevent transaction deadlocks between
@@ -746,7 +746,6 @@
    Set<ByteString> set = new HashSet<ByteString>();
    int substrLength = indexConfig.getSubstringLength();
    byte[] keyBytes;
    // Example: The value is ABCDE and the substring length is 3.
    // We produce the keys ABC BCD CDE DE E
@@ -757,7 +756,7 @@
    for (int i = 0, remain = value.length; remain > 0; i++, remain--)
    {
      int len = Math.min(substrLength, remain);
      keyBytes = makeSubstringKey(value, i, len);
      byte[] keyBytes = makeSubstringKey(value, i, len);
      set.add(ByteString.wrap(keyBytes));
    }
@@ -771,6 +770,9 @@
   */
  private EntryIDSet matchSubstring(byte[] bytes)
  {
    // FIXME replace this code with SDK's
    // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.createIndexQuery()
    int substrLength = indexConfig.getSubstringLength();
    // There are two cases, depending on whether the user-provided
@@ -818,9 +820,7 @@
      for (int first = 0, last = substrLength;
           last <= bytes.length; first++, last++)
      {
        byte[] keyBytes;
        keyBytes = makeSubstringKey(bytes, first, substrLength);
        set.add(keyBytes);
        set.add(makeSubstringKey(bytes, first, substrLength));
      }
      EntryIDSet results = new EntryIDSet();
@@ -856,6 +856,9 @@
   */
  private EntryIDSet matchInitialSubstring(byte[] bytes)
  {
    // FIXME replace this code with SDK's
    // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.createIndexQuery()
    // Iterate through all the keys that have this value as the prefix.
    // Set the lower bound for a range search.
@@ -1753,6 +1756,7 @@
      String name =
        entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID();
      int indexEntryLimit = cfg.getIndexEntryLimit();
      JEIndexConfig config = new JEIndexConfig(cfg.getSubstringLength());
      if (cfg.getIndexType().contains(LocalDBIndexCfgDefn.IndexType.EQUALITY))
      {
@@ -1880,8 +1884,7 @@
      {
        if(substringIndex == null)
        {
          Indexer substringIndexer = new SubstringIndexer(
              attrType, cfg.getSubstringLength());
          Indexer substringIndexer = new SubstringIndexer(attrType, config);
          substringIndex = new Index(name + ".substring",
                                     substringIndexer,
                                     state,
@@ -1914,8 +1917,7 @@
          if(indexConfig.getSubstringLength() !=
              cfg.getSubstringLength())
          {
            Indexer substringIndexer = new SubstringIndexer(
                attrType, cfg.getSubstringLength());
            Indexer substringIndexer = new SubstringIndexer(attrType, config);
            this.substringIndex.setIndexer(substringIndexer);
          }
        }
@@ -2076,7 +2078,6 @@
        {
          extensibleIndexes = new ExtensibleMatchingRuleIndex();
        }
        IndexConfig config = new JEIndexConfig(cfg.getSubstringLength());
        for(String ruleName:extensibleRules)
        {
          ExtensibleMatchingRule rule =
@@ -2091,11 +2092,7 @@
          Map<String,Index> indexMap = new HashMap<String,Index>();
          for(ExtensibleIndexer indexer: rule.getIndexers(config))
          {
            String indexerId = indexer.getExtensibleIndexID();
            String indexID =
                  attrType.getNameOrOID()  + "."
                   + indexer.getPreferredIndexName()
                   + "." + indexerId;
            String indexID = attrType.getNameOrOID() + "." + indexer.getIndexID();
            if(!extensibleIndexes.isIndexPresent(indexID))
            {
              Indexer extensibleIndexer =
@@ -2144,10 +2141,10 @@
              }
            }
            extensibleIndexes.addRule(indexID, rule);
            indexMap.put(indexerId,extensibleIndexes.getIndex(indexID));
            indexMap.put(indexer.getExtensibleIndexID(), extensibleIndexes.getIndex(indexID));
          }
          IndexQueryFactory<IndexQuery> factory =
                  new IndexQueryFactoryImpl(indexMap);
              new IndexQueryFactoryImpl(indexMap, config);
          extensibleIndexes.addQueryFactory(rule, factory);
        }
        //Some rules might have been removed from the configuration.
@@ -2172,9 +2169,7 @@
              List<String> ids = new ArrayList<String>();
              for(ExtensibleIndexer indexer: rule.getIndexers(config))
              {
                String id = attrType.getNameOrOID()  + "."
                 + indexer.getPreferredIndexName()
                 + "." + indexer.getExtensibleIndexID();
                String id = attrType.getNameOrOID()  + "." + indexer.getIndexID();
                rules.addAll(extensibleIndexes.getRules(id));
                ids.add(id);
              }
@@ -2620,16 +2615,14 @@
      if(debugBuffer != null)
      {
        debugBuffer.append("[INDEX:");
        IndexConfig config =
        JEIndexConfig config =
                new JEIndexConfig(indexConfig.getSubstringLength());
        for(ExtensibleIndexer indexer :  rule.getIndexers(config))
        {
          debugBuffer.append(" ")
                     .append(extensibleFilter.getAttributeType().getNameOrOID())
                     .append(".")
                     .append(indexer.getPreferredIndexName())
                     .append(".")
                     .append(indexer.getExtensibleIndexID());
                     .append(indexer.getIndexID());
        }
        debugBuffer.append("]");
      }
@@ -2901,7 +2894,7 @@
  /**
   * This class extends the IndexConfig for JE Backend.
   */
  private class JEIndexConfig extends IndexConfig
  private class JEIndexConfig implements IndexingOptions
  {
    /** The length of the substring index. */
    private int substringLength;
@@ -2916,13 +2909,9 @@
      this.substringLength = substringLength;
    }
    /**
     * Returns the length of the substring.
     * @return the length of the substring.
     */
    /** {@inheritDoc} */
    @Override
    public int getSubstringLength()
    public int substringKeySize()
    {
      return substringLength;
    }
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
@@ -26,8 +26,10 @@
 */
package org.opends.server.backends.jeb;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import java.util.*;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.opends.server.api.ExtensibleIndexer;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
@@ -35,8 +37,6 @@
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import java.util.*;
/**
 * An implementation of an Indexer for attribute equality.
 */
@@ -74,6 +74,7 @@
   * used to name an index created using this object.
   * @return A string representation of this object.
   */
  @Override
  public String toString()
  {
    return attributeType.getNameOrOID() + ".equality";
@@ -85,6 +86,7 @@
   *
   * @return A byte array comparator.
   */
  @Override
  public Comparator<byte[]> getComparator()
  {
    return comparator;
@@ -98,6 +100,7 @@
   * @param entry The entry.
   * @param keys The set into which the generated keys will be inserted.
   */
  @Override
  public void indexEntry(Entry entry, Set<byte[]> keys)
  {
    List<Attribute> attrList =
@@ -118,6 +121,7 @@
   * @param newEntry The new entry contents.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  @Override
  public void replaceEntry(Entry oldEntry, Entry newEntry,
                           Map<byte[], Boolean> modifiedKeys)
  {
@@ -140,6 +144,7 @@
   * @param mods The set of modifications that were applied to the entry.
   * @param modifiedKeys The map into which the modified keys will be inserted.
   */
  @Override
  public void modifyEntry(Entry oldEntry, Entry newEntry,
                          List<Modification> mods,
                          Map<byte[], Boolean> modifiedKeys)
@@ -163,23 +168,25 @@
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
      for (AttributeValue value : attr)
      {
        try
        for (AttributeValue value : attr)
        {
          byte[] keyBytes = value.getNormalizedValue().toByteArray();
          getKeys(value, keys);
        }
      }
    }
  }
          keys.add(keyBytes);
        }
        catch (DirectoryException e)
        {
          logger.traceException(e);
        }
      }
  private void getKeys(AttributeValue value, Set<byte[]> keys)
  {
    try
    {
      keys.add(value.getNormalizedValue().toByteArray());
    }
    catch (DirectoryException e)
    {
      logger.traceException(e);
    }
  }
@@ -199,31 +206,21 @@
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
      for (AttributeValue value : attr)
      {
        try
        for (AttributeValue value : attr)
        {
          byte[] keyBytes = value.getNormalizedValue().toByteArray();
          Boolean cInsert = modifiedKeys.get(keyBytes);
          if(cInsert == null)
          {
            modifiedKeys.put(keyBytes, insert);
          }
          else if(!cInsert.equals(insert))
          {
            modifiedKeys.remove(keyBytes);
          }
        }
        catch (DirectoryException e)
        {
          logger.traceException(e);
          getKeys(value, modifiedKeys, insert);
        }
      }
    }
  }
  private void getKeys(AttributeValue value, Map<byte[], Boolean> modifiedKeys,
      Boolean insert)
  {
    Set<byte[]> keys = new HashSet<byte[]>();
    getKeys(value, keys);
    ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys);
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java
@@ -24,28 +24,21 @@
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2014 ForgeRock AS
 */
package org.opends.server.backends.jeb;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.LockMode;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.forgerock.i18n.LocalizableMessage;
import org.opends.server.api.IndexQueryFactory;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import static org.opends.messages.JebMessages.
    INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED;
import static org.opends.messages.JebMessages.
    INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED;
import static org.opends.messages.JebMessages.
    INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.LockMode;
import static org.opends.messages.JebMessages.*;
/**
 * This class is an implementation of IndexQueryFactory which creates
@@ -54,30 +47,31 @@
public final class IndexQueryFactoryImpl implements
    IndexQueryFactory<IndexQuery>
{
  /**
   * The Map containing the string type identifier and the corresponding
   * index.
   * The Map containing the string type identifier and the corresponding index.
   */
  private Map<String, Index> indexMap;
  private final Map<String, Index> indexMap;
  private final IndexingOptions indexingOptions;
  /**
   * Creates a new IndexQueryFactoryImpl object.
   *
   * @param indexMap
   *          A map containing the index id and the corresponding index.
   * @param indexingOptions
   *          The options to use for indexing
   */
  public IndexQueryFactoryImpl(Map<String, Index> indexMap)
  public IndexQueryFactoryImpl(Map<String, Index> indexMap, IndexingOptions indexingOptions)
  {
    this.indexMap = indexMap;
    this.indexingOptions = indexingOptions;
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public IndexQuery createExactMatchQuery(final String indexID,
      final ByteSequence value)
  {
@@ -122,9 +116,8 @@
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public IndexQuery createRangeMatchQuery(final String indexID,
      final ByteSequence lowerBound, final ByteSequence upperBound,
      final boolean includeLowerBound, final boolean includeUpperBound)
@@ -168,9 +161,8 @@
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public IndexQuery createIntersectionQuery(
      Collection<IndexQuery> subqueries)
  {
@@ -179,9 +171,8 @@
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public IndexQuery createUnionQuery(Collection<IndexQuery> subqueries)
  {
    return IndexQuery.createUnionIndexQuery(subqueries);
@@ -195,6 +186,7 @@
   * It returns an empty EntryIDSet object when either all or no record
   * sets are requested.
   */
  @Override
  public IndexQuery createMatchAllQuery()
  {
    return new IndexQuery()
@@ -207,4 +199,11 @@
        }
      };
  }
  /** {@inheritDoc} */
  @Override
  public IndexingOptions getIndexingOptions()
  {
    return indexingOptions;
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
@@ -22,25 +22,22 @@
 *
 *
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2014 ForgeRock AS
 */
package org.opends.server.backends.jeb;
import org.opends.server.api.ExtensibleIndexer;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.api.ExtensibleMatchingRule;
import org.opends.server.types.Attribute;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opends.server.api.ExtensibleIndexer;
import org.opends.server.api.ExtensibleMatchingRule;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.types.Attribute;
/**
 *This class implements an Indexer for extensible matching rules in JE Backend.
@@ -179,13 +176,12 @@
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
      for (AttributeValue value : attr)
      {
        extensibleIndexer.getKeys(value, keys);
        for (AttributeValue value : attr)
        {
          extensibleIndexer.getKeys(value, keys);
        }
      }
    }
  }
@@ -208,13 +204,12 @@
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
      for (AttributeValue value : attr)
      {
        extensibleIndexer.getKeys(value,modifiedKeys,insert);
        for (AttributeValue value : attr)
        {
          extensibleIndexer.getKeys(value, modifiedKeys, insert);
        }
      }
    }
  }
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
@@ -27,12 +27,14 @@
package org.opends.server.backends.jeb;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.DecodeException;
import org.opends.server.api.ExtensibleIndexer;
import org.opends.server.api.OrderingMatchingRule;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -167,24 +169,25 @@
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
      for (AttributeValue value : attr)
      {
        try
        for (AttributeValue value : attr)
        {
          byte[] keyBytes = orderingRule.normalizeAttributeValue(value.getValue())
              .toByteArray();
          getKeys(value, keys);
        }
      }
    }
  }
          keys.add(keyBytes);
        }
        catch (DecodeException e)
        {
          logger.traceException(e);
        }
      }
  private void getKeys(AttributeValue value, Set<byte[]> keys)
  {
    try
    {
      keys.add(orderingRule.normalizeAttributeValue(value.getValue()).toByteArray());
    }
    catch (DecodeException e)
    {
      logger.traceException(e);
    }
  }
@@ -205,32 +208,21 @@
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
      for (AttributeValue value : attr)
      {
        try
        for (AttributeValue value : attr)
        {
          byte[] keyBytes =
               orderingRule.normalizeAttributeValue(value.getValue()).toByteArray();
          Boolean cInsert = modifiedKeys.get(keyBytes);
          if(cInsert == null)
          {
            modifiedKeys.put(keyBytes, insert);
          }
          else if(!cInsert.equals(insert))
          {
            modifiedKeys.remove(keyBytes);
          }
        }
        catch (DecodeException e)
        {
          logger.traceException(e);
          getKeys(value, modifiedKeys, insert);
        }
      }
    }
  }
  private void getKeys(AttributeValue value, Map<byte[], Boolean> modifiedKeys,
      Boolean insert)
  {
    Set<byte[]> keys = new HashSet<byte[]>();
    getKeys(value, keys);
    ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys);
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
@@ -27,12 +27,15 @@
package org.opends.server.backends.jeb;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import org.opends.server.api.ExtensibleIndexer;
import org.opends.server.api.SubstringMatchingRule;
import org.opends.server.types.*;
@@ -56,22 +59,21 @@
   * generate index keys.
   */
  private AttributeType attributeType;
  /**
   * The substring length.
   */
  private int substrLength;
  private IndexingOptions indexingOptions;
  /**
   * Create a new attribute substring indexer for the given index configuration.
   * @param attributeType The attribute type for which an indexer is
   * required.
   * @param substringLength The decomposed substring length.
   *
   * @param attributeType
   *          The attribute type for which an indexer is required.
   * @param indexingOptions
   *          The decomposed substring length.
   */
  public SubstringIndexer(AttributeType attributeType, int substringLength)
  public SubstringIndexer(AttributeType attributeType,
      IndexingOptions indexingOptions)
  {
    this.attributeType = attributeType;
    this.substrLength = substringLength;
    this.indexingOptions = indexingOptions;
  }
  /**
@@ -169,25 +171,13 @@
    if (attrList == null) return;
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
      //Get the substring matching rule.
      SubstringMatchingRule rule =
              attr.getAttributeType().getSubstringMatchingRule();
      for (AttributeValue value : attr)
      {
        try
        SubstringMatchingRule rule =
            attr.getAttributeType().getSubstringMatchingRule();
        for (AttributeValue value : attr)
        {
          byte[] normalizedBytes = rule.normalizeAttributeValue(value.getValue()).
                  toByteArray();
          substringKeys(normalizedBytes, keys);
        }
        catch (DecodeException e)
        {
          logger.traceException(e);
          getKeys(rule, value, keys);
        }
      }
    }
@@ -198,24 +188,32 @@
   * The ID of the entry containing this value should be inserted
   * into the list of each of these keys.
   *
   * @param value A byte array containing the normalized attribute value
   * @param set A set into which the keys will be inserted.
   * @param attrValue A byte array containing the normalized attribute value
   * @param keys A set into which the keys will be inserted.
   */
  private void substringKeys(byte[] value, Set<byte[]> set)
  {
    byte[] keyBytes;
    // 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 = value.length; remain > 0; i++, remain--)
  private void getKeys(SubstringMatchingRule rule, AttributeValue attrValue,
      Set<byte[]> keys)
  { // TODO merge with ExtensibleIndexer.getKeys(attrValue, keys);
    try
    {
      int len = Math.min(substrLength, remain);
      keyBytes = makeSubstringKey(value, i, len);
      set.add(keyBytes);
      byte[] value = rule.normalizeAttributeValue(attrValue.getValue()).toByteArray();
      // 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.
      final int substringKeySize = indexingOptions.substringKeySize();
      for (int i = 0, remain = value.length; remain > 0; i++, remain--)
      {
        int len = Math.min(substringKeySize, remain);
        keys.add(makeSubstringKey(value, i, len));
      }
    }
    catch (DecodeException e)
    {
      logger.traceException(e);
    }
  }
@@ -251,26 +249,13 @@
    for (Attribute attr : attrList)
    {
      if (attr.isVirtual())
      if (!attr.isVirtual())
      {
        continue;
      }
            //Get the substring matching rule.
      SubstringMatchingRule rule =
              attr.getAttributeType().getSubstringMatchingRule();
      for (AttributeValue value : attr)
      {
        try
        SubstringMatchingRule rule =
            attr.getAttributeType().getSubstringMatchingRule();
        for (AttributeValue value : attr)
        {
          byte[] normalizedBytes = rule.normalizeAttributeValue(value.getValue())
                  .toByteArray();
          substringKeys(normalizedBytes, modifiedKeys, insert);
        }
        catch (DecodeException e)
        {
          logger.traceException(e);
          getKeys(rule, value, modifiedKeys, insert);
        }
      }
    }
@@ -287,41 +272,12 @@
   * @param insert <code>true</code> if generated keys should
   * be inserted or <code>false</code> otherwise.
   */
  private void substringKeys(byte[] value,
                             Map<byte[], Boolean> modifiedKeys,
                             Boolean insert)
  {
    byte[] keyBytes;
    // 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 = value.length; remain > 0; i++, remain--)
    {
      int len = Math.min(substrLength, remain);
      keyBytes = makeSubstringKey(value, i, len);
      Boolean cInsert = modifiedKeys.get(keyBytes);
      if(cInsert == null)
      {
        modifiedKeys.put(keyBytes, insert);
      }
      else if(!cInsert.equals(insert))
      {
        modifiedKeys.remove(keyBytes);
      }
    }
  private void getKeys(SubstringMatchingRule rule, AttributeValue value,
      Map<byte[], Boolean> modifiedKeys, Boolean insert)
  { // TODO merge with ExtensibleIndexer.getKeys(attrValue, modifiedKeys, insert);
    Set<byte[]> keys = new HashSet<byte[]>();
    getKeys(rule, value, keys);
    ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys);
  }
  /**
   * Return the substring length for an indexer.
   *
   * @return  The substring length configured for an sub string indexer.
   */
  public int getSubStringLen()
  {
    return substrLength;
  }
}
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java
@@ -38,6 +38,8 @@
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.meta.CollationMatchingRuleCfgDefn.MatchingRuleType;
import org.opends.server.admin.std.server.CollationMatchingRuleCfg;
@@ -45,7 +47,10 @@
import org.opends.server.backends.jeb.AttributeIndex;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.*;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.InitializationException;
import org.opends.server.util.StaticUtils;
import static org.opends.messages.ConfigMessages.*;
@@ -957,7 +962,8 @@
     * {@inheritDoc}
     */
    @Override
    public Collection<ExtensibleIndexer> getIndexers(IndexConfig config)
    public Collection<ExtensibleIndexer> getIndexers(
        IndexingOptions indexingOptions)
    {
      if (indexer == null)
      {
@@ -1420,7 +1426,8 @@
    @Override
    public ConditionResult valuesMatch(ByteSequence attributeValue,
        ByteSequence assertionValue)
    {
    { // FIXME Code similar to
      // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.matches()
      int valueLength = attributeValue.length() - 4;
      int valuePos = 0; // position in the value bytes array.
@@ -1526,30 +1533,25 @@
     */
    @Override
    public final Collection<ExtensibleIndexer> getIndexers(
        IndexConfig config)
        IndexingOptions indexingOptions)
    {
      Collection<ExtensibleIndexer> indexers =
          new ArrayList<ExtensibleIndexer>();
      int substrLength = 6; // Default substring length;
      if (subIndexer == null)
      {
        if (config != null)
        if (indexingOptions != null)
        {
          substrLength = config.getSubstringLength();
          substrLength = indexingOptions.substringKeySize();
        }
        subIndexer =
            new CollationSubstringExtensibleIndexer(this, substrLength);
      }
      else
      else if (indexingOptions != null
          && indexingOptions.substringKeySize() != subIndexer
              .getSubstringLength())
      {
        if (config != null)
        {
          if (config.getSubstringLength() != subIndexer
              .gerSubstringLength())
          {
            subIndexer.setSubstringLength(substrLength);
          }
        }
        subIndexer.setSubstringLength(substrLength);
      }
      if (indexer == null)
@@ -1573,15 +1575,15 @@
     * @param set
     *          A set into which the keys will be inserted.
     */
    private void subtringKeys(ByteString attValue, Set<byte[]> keys)
    {
    private void substringKeys(ByteString attValue, Set<byte[]> keys)
    { // TODO merge with ExtensibleIndexer.getKeys(attrValue, keys);
      // TODO and with AbstractSubstringMatchingRuleImpl.SubstringIndexer.createKeys();
      String value = attValue.toString();
      int keyLength = subIndexer.gerSubstringLength();
      int keyLength = subIndexer.getSubstringLength();
      for (int i = 0, remain = value.length(); remain > 0; i++, remain--)
      {
        int len = Math.min(keyLength, remain);
        byte[] keyBytes = makeSubstringKey(value, i, len);
        keys.add(keyBytes);
        keys.add(makeSubstringKey(value, i, len));
      }
    }
@@ -1600,23 +1602,10 @@
     */
    private void substringKeys(ByteString attValue,
        Map<byte[], Boolean> modifiedKeys, Boolean insert)
    {
      String value = attValue.toString();
      int keyLength = subIndexer.gerSubstringLength();
      for (int i = 0, remain = value.length(); remain > 0; i++, remain--)
      {
        int len = Math.min(keyLength, remain);
        byte[] keyBytes = makeSubstringKey(value, i, len);
        Boolean cinsert = modifiedKeys.get(keyBytes);
        if (cinsert == null)
        {
          modifiedKeys.put(keyBytes, insert);
        }
        else if (!cinsert.equals(insert))
        {
          modifiedKeys.remove(keyBytes);
        }
      }
    { // TODO merge with ExtensibleIndexer.getKeys(attrValue, modifiedKeys, insert);
      Set<byte[]> keys = new TreeSet<byte[]>();
      substringKeys(attValue, keys);
      ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys);
    }
@@ -1655,7 +1644,8 @@
     */
    private <T> T matchInitialSubstring(String value,
        IndexQueryFactory<T> factory)
    {
    { // FIXME Code similar to
      // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.rangeMatch()
      byte[] lower = makeSubstringKey(value, 0, value.length());
      byte[] upper = new byte[lower.length];
      System.arraycopy(lower, 0, upper, 0, lower.length);
@@ -1695,9 +1685,10 @@
     */
    private <T> T matchSubstring(String value,
        IndexQueryFactory<T> factory)
    {
    { // FIXME Code similar to
      // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.substringMatch()
      T intersectionQuery;
      int substrLength = subIndexer.gerSubstringLength();
      int substrLength = subIndexer.getSubstringLength();
      if (value.length() < substrLength)
      {
@@ -1733,17 +1724,13 @@
             last <= value.length();
             first++, last++)
        {
          byte[] keyBytes;
          keyBytes = makeSubstringKey(value, first, substrLength);
          set.add(keyBytes);
          set.add(makeSubstringKey(value, first, substrLength));
        }
        for (byte[] keyBytes : set)
        {
          T single =
              factory.createExactMatchQuery(subIndexer
                  .getExtensibleIndexID(), ByteString.wrap(keyBytes));
          queryList.add(single);
          queryList.add(factory.createExactMatchQuery(
              subIndexer.getExtensibleIndexID(), ByteString.wrap(keyBytes)));
        }
        intersectionQuery = factory.createIntersectionQuery(queryList);
      }
@@ -1758,7 +1745,8 @@
    @Override
    public <T> T createIndexQuery(ByteSequence assertionValue,
        IndexQueryFactory<T> factory) throws DecodeException
    {
    { // FIXME Code similar to
      // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.createIndexQuery()?
      Assertion assertion = parseAssertion(assertionValue);
      String subInitial = assertion.getInitial();
      List<String> subAny = assertion.getAny();
@@ -2167,40 +2155,11 @@
      }
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public final void getKeys(AttributeValue value,
        Map<byte[], Boolean> modifiedKeys, Boolean insert)
    public String getIndexID()
    {
      Set<byte[]> keys = new HashSet<byte[]>();
      getKeys(value, keys);
      for (byte[] key : keys)
      {
        Boolean cInsert = modifiedKeys.get(key);
        if (cInsert == null)
        {
          modifiedKeys.put(key, insert);
        }
        else if (!cInsert.equals(insert))
        {
          modifiedKeys.remove(key);
        }
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public String getPreferredIndexName()
    {
      return matchingRule.getIndexName();
      return matchingRule.getIndexName() + "." + getExtensibleIndexID();
    }
  }
@@ -2242,7 +2201,7 @@
    @Override
    public void getKeys(AttributeValue value, Set<byte[]> keys)
    {
      matchingRule.subtringKeys(value.getValue(), keys);
      matchingRule.substringKeys(value.getValue(), keys);
    }
@@ -2254,19 +2213,14 @@
    public void getKeys(AttributeValue attValue,
        Map<byte[], Boolean> modifiedKeys, Boolean insert)
    {
      matchingRule.substringKeys(attValue.getValue(), modifiedKeys,
          insert);
      matchingRule.substringKeys(attValue.getValue(), modifiedKeys, insert);
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public String getPreferredIndexName()
    public String getIndexID()
    {
      return matchingRule.getIndexName();
      return matchingRule.getIndexName() + "." + getExtensibleIndexID();
    }
@@ -2287,8 +2241,8 @@
     *
     * @return The length of the substring.
     */
    private int gerSubstringLength()
    {
    private int getSubstringLength()
    {// TODO JNR remove
      return substringLen;
    }
@@ -2301,9 +2255,10 @@
     *          The substring length.
     */
    private void setSubstringLength(int substringLen)
    {
    {// TODO JNR remove
      this.substringLen = substringLen;
    }
  }
  /**
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java
@@ -38,13 +38,14 @@
import org.forgerock.opendj.ldap.ByteStringBuilder;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import org.opends.server.admin.std.server.MatchingRuleCfg;
import org.opends.server.api.*;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.IndexConfig;
import org.opends.server.types.InitializationException;
import org.opends.server.util.StaticUtils;
@@ -403,7 +404,8 @@
    * {@inheritDoc}
    */
    @Override
    public Collection<ExtensibleIndexer> getIndexers(IndexConfig config)
    public Collection<ExtensibleIndexer> getIndexers(
        IndexingOptions indexingOptions)
    {
      if(indexer == null)
      {
@@ -630,40 +632,11 @@
      }
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public final void getKeys(AttributeValue value,
        Map<byte[], Boolean> modifiedKeys, Boolean insert)
    public String getIndexID()
    {
      Set<byte[]> keys = new HashSet<byte[]>();
      getKeys(value, keys);
      for (byte[] key : keys)
      {
        Boolean cInsert = modifiedKeys.get(key);
        if (cInsert == null)
        {
          modifiedKeys.put(key, insert);
        }
        else if (!cInsert.equals(insert))
        {
          modifiedKeys.remove(key);
        }
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public String getPreferredIndexName()
    {
      return RELATIVE_TIME_INDEX_NAME;
      return RELATIVE_TIME_INDEX_NAME + "." + getExtensibleIndexID();
    }
  }
@@ -674,7 +647,6 @@
   */
  private final class PartialDateAndTimeMatchingRule
          extends TimeBasedMatchingRule
          implements ExtensibleMatchingRule
  {
     /**
      * Indexer associated with this instance.
@@ -1050,7 +1022,8 @@
      * {@inheritDoc}
      */
    @Override
    public Collection<ExtensibleIndexer> getIndexers(IndexConfig config)
    public Collection<ExtensibleIndexer> getIndexers(
        IndexingOptions indexingOptions)
    {
      if(indexer == null)
      {
@@ -1237,40 +1210,11 @@
      matchingRule.timeKeys(value.getValue(), keys);
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public void getKeys(AttributeValue attValue,
        Map<byte[], Boolean> modifiedKeys, Boolean insert)
    public String getIndexID()
    {
      Set<byte[]> keys = new HashSet<byte[]>();
      getKeys(attValue, keys);
      for (byte[] key : keys)
      {
        Boolean cInsert = modifiedKeys.get(key);
        if (cInsert == null)
        {
          modifiedKeys.put(key, insert);
        }
        else if (!cInsert.equals(insert))
        {
          modifiedKeys.remove(key);
        }
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public String getPreferredIndexName()
    {
      return PARTIAL_DATE_TIME_INDEX_NAME;
      return PARTIAL_DATE_TIME_INDEX_NAME + "." + getExtensibleIndexID();
    }
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/types/IndexConfig.java
File was deleted
opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -31,7 +31,9 @@
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.server.AdminTestCaseUtils;
import org.opends.server.admin.std.meta.LocalDBBackendCfgDefn;
@@ -45,7 +47,12 @@
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.types.Attribute;
import org.opends.server.types.Attributes;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.types.RDN;
import org.opends.server.util.Base64;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -57,6 +64,7 @@
import static org.assertj.core.api.Assertions.*;
import static org.forgerock.opendj.ldap.ConditionResult.*;
import static org.mockito.Mockito.*;
import static org.testng.Assert.*;
/**
@@ -842,9 +850,7 @@
      assertIndexContainsID(equalityIndexer, entry, index.equalityIndex,
          entryID, FALSE);
      Indexer substringIndexer =
          new SubstringIndexer(index.getAttributeType(),
                   index.getConfiguration().getSubstringLength());
      Indexer substringIndexer = newSubstringIndexer(index);
      assertIndexContainsID(substringIndexer, entry, index.substringIndex,
          entryID, FALSE);
@@ -858,6 +864,14 @@
    }
  }
  private SubstringIndexer newSubstringIndexer(AttributeIndex index)
  {
    final IndexingOptions options = mock(IndexingOptions.class);
    when(options.substringKeySize()).thenReturn(
        index.getConfiguration().getSubstringLength());
    return new SubstringIndexer(index.getAttributeType(), options);
  }
  private void assertIndexContainsID(Indexer indexer, Entry entry, Index index,
      EntryID entryID)
  {
@@ -932,8 +946,7 @@
      assertIndexContainsID(orderingIndexer, oldEntry, index.orderingIndex,
          entryID, FALSE);
      Indexer substringIndexer = new SubstringIndexer(index.getAttributeType(),
                                              index.getConfiguration().getSubstringLength());
      Indexer substringIndexer = newSubstringIndexer(index);
      assertIndexContainsID(substringIndexer, entry, index.substringIndex,
          entryID, TRUE);
      assertIndexContainsID(substringIndexer, oldEntry, index.substringIndex,
@@ -1096,12 +1109,10 @@
      equalityIndexer = new EqualityIndexer(nameIndex.getAttributeType());
      assertIndexContainsID(equalityIndexer, entry, nameIndex.equalityIndex, entryID);
      substringIndexer = new SubstringIndexer(titleIndex.getAttributeType(),
          titleIndex.getConfiguration().getSubstringLength());
      substringIndexer = newSubstringIndexer(titleIndex);
      assertIndexContainsID(substringIndexer, entry, titleIndex.substringIndex, entryID);
      substringIndexer = new SubstringIndexer(nameIndex.getAttributeType(),
          nameIndex.getConfiguration().getSubstringLength());
      substringIndexer = newSubstringIndexer(nameIndex);
      assertIndexContainsID(substringIndexer, entry, nameIndex.substringIndex, entryID);
    }
    finally