From 4609647b9acd61e11ce2b2c65c88efbc9e601489 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Thu, 06 Mar 2014 23:25:34 +0000
Subject: [PATCH] OPENDJ-1308 Migrate schema support

---
 opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java |   31 +
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EqualityIndexer.java                         |   73 ++--
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java                     |   41 +-
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java                        |  148 +++------
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleIndexer.java                                |   82 +++-
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java                          |   73 +--
 /dev/null                                                                                                            |   40 --
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java                      |   69 ++--
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java                  |  141 +++-----
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleMatchingRule.java                           |   23 
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java                  |   80 ----
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java                   |   59 +-
 opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java                         |   66 +--
 13 files changed, 374 insertions(+), 552 deletions(-)

diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleIndexer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleIndexer.java
index 124460b..304d7f8 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleIndexer.java
+++ b/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);
+      }
+    }
+  }
 }
\ No newline at end of file
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleMatchingRule.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleMatchingRule.java
index 5a81398..4c2abe5 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ExtensibleMatchingRule.java
+++ b/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);
 
 
 
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/IndexQueryFactory.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/IndexQueryFactory.java
deleted file mode 100644
index d0a6f1a..0000000
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/IndexQueryFactory.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at legal-notices/CDDLv1_0.txt.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information:
- *      Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- *      Copyright 2009 Sun Microsystems, Inc.
- *      Portions Copyright 2014 ForgeRock AS
- */
-package org.opends.server.api;
-
-
-
-import java.util.Collection;
-
-import org.forgerock.opendj.ldap.ByteSequence;
-
-
-
-/**
- * A factory for creating arbitrarily complex index queries. This
- * interface is implemented by the underlying backend implementation
- * and passed to extensible matching rules so that they can construct
- * arbitrarily complex index queries.
- *
- * @param <T>
- *          The type of query created by this factory.
- */
-@org.opends.server.types.PublicAPI(
-    stability = org.opends.server.types.StabilityLevel.VOLATILE,
-    mayInstantiate = false,
-    mayExtend = true,
-    mayInvoke = false)
-public interface IndexQueryFactory<T>
-{
-
-  /**
-   * Returns a query requesting an index record matching the provided
-   * key.
-   *
-   * @param indexID
-   *          An identifier of the index type.
-   * @param key
-   *          A byte sequence containing the key.
-   * @return A query requesting the index record matching the key.
-   */
-  T createExactMatchQuery(String indexID, ByteSequence key);
-
-
-
-  /**
-   * Returns a query requesting all index records. A backend
-   * implementation may choose to return all or no records as part of
-   * the optimization.
-   *
-   * @return A query requesting all index records.
-   */
-  T createMatchAllQuery();
-
-
-
-  /**
-   * Returns a query requesting all index records in the specified
-   * range.
-   *
-   * @param indexID
-   *          An identifier of the index type.
-   * @param lower
-   *          The lower bound of the range. A 0 length byte array
-   *          indicates no lower bound and the range will start from
-   *          the smallest key.
-   * @param upper
-   *          The upper bound of the range. A 0 length byte array
-   *          indicates no upper bound and the range will end at the
-   *          largest key.
-   * @param lowerIncluded
-   *          true if a key exactly matching the lower bound is
-   *          included in the range, false if only keys strictly
-   *          greater than the lower bound are included.This value
-   *          is ignored if the lower bound is not specified.
-   * @param upperIncluded
-   *          true if a key exactly matching the upper bound is
-   *          included in the range, false if only keys strictly
-   *          less than the upper bound are included. This value is
-   *          ignored if the upper bound is not specified.
-   * @return A query requesting all index records in the specified
-   *         range.
-   */
-  T createRangeMatchQuery(String indexID, ByteSequence lower,
-      ByteSequence upper, boolean lowerIncluded,
-      boolean upperIncluded);
-
-
-
-  /**
-   * Returns a query which returns the intersection of a collection of
-   * sub-queries.
-   *
-   * @param subquery
-   *          A collection of sub-queries.
-   * @return A query which returns the intersection of a collection of
-   *         sub-queries.
-   */
-  T createIntersectionQuery(Collection<T> subquery);
-
-
-
-  /**
-   * Returns a query which combines the results of a collection of
-   * sub-queries.
-   *
-   * @param subquery
-   *          A collection of sub-queries.
-   * @return A query which combines the results of a collection of
-   *         sub-queries.
-   */
-  T createUnionQuery(Collection<T> subquery);
-}
\ No newline at end of file
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
index c15b923..49db13d 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
+++ b/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);
+  }
 }
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
index a68545c..c5449f2 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
+++ b/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;
     }
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EqualityIndexer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
index 9415635..6ae0286 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
+++ b/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);
+  }
 }
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java
index 282a097..ffcdca7 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java
+++ b/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;
+  }
 }
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
index 29f3fc4..a8b8c0e 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/JEExtensibleIndexer.java
+++ b/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);
+        }
       }
     }
   }
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
index ab2511b..c7b54c2 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
+++ b/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);
+  }
 }
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
index c742496..6547454 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
+++ b/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;
-  }
 }
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java
index eca9268..a6a5b15 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/CollationMatchingRuleFactory.java
+++ b/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;
     }
+
   }
 
   /**
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java
index 06b5e16..7914dbb 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/TimeBasedMatchingRuleFactory.java
+++ b/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();
     }
 
 
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/types/IndexConfig.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/types/IndexConfig.java
deleted file mode 100644
index d80e0a0..0000000
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/types/IndexConfig.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at legal-notices/CDDLv1_0.txt.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information:
- *      Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- *      Copyright 2009 Sun Microsystems, Inc.
- */
-
-
-package org.opends.server.types;
-
-/**
- * This class represents the configuration of an index.
- */
-public abstract class IndexConfig
-{
-  /**
-   * Returns the length of a substring.
-   * @return the length of the substring.
-   */
-  public abstract int getSubstringLength();
-}
diff --git a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
index 7f33026..d1b9c97 100644
--- a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
+++ b/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

--
Gitblit v1.10.0