Index: src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexEditorTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexEditorTest.java	(revision 0)
+++ src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexEditorTest.java	(revision 0)
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.JcrConstants.NT_BASE;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexHookProvider;
+import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexLookup;
+import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
+import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.commit.EditorHook;
+import org.apache.jackrabbit.oak.spi.query.Filter;
+import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+public class IndexEditorTest {
+
+    private NodeState root = new InitialContent().initialize(EMPTY_NODE);
+
+    private NodeBuilder builder = root.builder();
+
+    /**
+     * Simple Test
+     * <ul>
+     * <li>Add an index definition</li>
+     * <li>Add some content</li>
+     * <li>Search & verify</li>
+     * </ul>
+     * 
+     */
+    @Test
+    public void test() throws Exception {
+        createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
+                false, ImmutableSet.of("foo"), null);
+        createIndexDefinition(
+                builder.child("newchild").child("other").child("oak:index"),
+                "subIndex", true, false, ImmutableSet.of("foo"), null);
+
+        NodeState before = builder.getNodeState();
+
+        // Add nodes
+        builder.child("testRoot").setProperty("foo", "abc");
+        builder.child("newchild").child("other").child("testChild")
+                .setProperty("foo", "xyz");
+
+        NodeState after = builder.getNodeState();
+
+        IndexEditorProvider p = new IndexEditorProvider(
+                new Property2IndexHookProvider());
+        EditorHook hook = new EditorHook(p);
+        NodeState indexed = hook.processCommit(before, after);
+
+        // first check that the index content nodes exist
+        checkPathExists(indexed, "oak:index", "rootIndex", ":index");
+        checkPathExists(indexed, "newchild", "other", "oak:index", "subIndex",
+                ":index");
+
+        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
+        assertEquals(ImmutableSet.of("testRoot"), find(lookup, "foo", "abc"));
+
+        Property2IndexLookup lookupChild = new Property2IndexLookup(indexed
+                .getChildNode("newchild").getChildNode("other"));
+        assertEquals(ImmutableSet.of("testChild"),
+                find(lookupChild, "foo", "xyz"));
+        assertEquals(ImmutableSet.of(), find(lookupChild, "foo", "abc"));
+
+    }
+
+    /**
+     * Reindex Test
+     * <ul>
+     * <li>Add some content</li>
+     * <li>Add an index definition with the reindex flag set</li>
+     * <li>Search & verify</li>
+     * </ul>
+     */
+    @Test
+    public void testReindex() throws Exception {
+        builder.child("testRoot").setProperty("foo", "abc");
+        NodeState before = builder.getNodeState();
+        createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
+                false, ImmutableSet.of("foo"), null);
+
+        NodeState after = builder.getNodeState();
+
+        IndexEditorProvider p = new IndexEditorProvider(
+                new Property2IndexHookProvider());
+        EditorHook hook = new EditorHook(p);
+        NodeState indexed = hook.processCommit(before, after);
+
+        // first check that the index content nodes exist
+        NodeState ns = checkPathExists(indexed, "oak:index", "rootIndex");
+        checkPathExists(ns, ":index");
+        PropertyState ps = ns.getProperty(REINDEX_PROPERTY_NAME);
+        assertNotNull(ps);
+        assertFalse(ps.getValue(Type.BOOLEAN));
+
+        // next, lookup
+        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
+        assertEquals(ImmutableSet.of("testRoot"), find(lookup, "foo", "abc"));
+    }
+
+    /**
+     * Reindex Test
+     * <ul>
+     * <li>Add some content & an index definition</li>
+     * <li>Update the index def by setting the reindex flag to true</li>
+     * <li>Search & verify</li>
+     * </ul>
+     */
+    @Test
+    public void testReindex2() throws Exception {
+        builder.child("testRoot").setProperty("foo", "abc");
+
+        createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
+                false, ImmutableSet.of("foo"), null).removeProperty("reindex");
+
+        NodeState before = builder.getNodeState();
+        builder.child("oak:index").child("rootIndex")
+                .setProperty(REINDEX_PROPERTY_NAME, true);
+        NodeState after = builder.getNodeState();
+
+        IndexEditorProvider p = new IndexEditorProvider(
+                new Property2IndexHookProvider());
+        EditorHook hook = new EditorHook(p);
+        NodeState indexed = hook.processCommit(before, after);
+
+        // first check that the index content nodes exist
+        NodeState ns = checkPathExists(indexed, "oak:index", "rootIndex");
+        checkPathExists(ns, ":index");
+        PropertyState ps = ns.getProperty(REINDEX_PROPERTY_NAME);
+        assertNotNull(ps);
+        assertFalse(ps.getValue(Type.BOOLEAN));
+
+        // next, lookup
+        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
+        assertEquals(ImmutableSet.of("testRoot"), find(lookup, "foo", "abc"));
+    }
+
+    @Test
+    public void testIndexDefinitions() throws Exception {
+        createIndexDefinition(builder.child("oak:index"), "existing", true,
+                false, ImmutableSet.of("foo"), null);
+
+        NodeState before = builder.getNodeState();
+        // Add index definition
+        createIndexDefinition(builder.child("oak:index"), "foo", true, false,
+                ImmutableSet.of("foo"), null);
+        createIndexDefinition(
+                builder.child("test").child("other").child("oak:index"),
+                "index2", true, false, ImmutableSet.of("foo"), null);
+        NodeState after = builder.getNodeState();
+
+        IndexEditorProvider p = new IndexEditorProvider(
+                new Property2IndexHookProvider());
+        EditorHook hook = new EditorHook(p);
+        NodeState indexed = hook.processCommit(before, after);
+
+        // check that the index content nodes exist
+        checkPathExists(indexed, "oak:index", "existing", ":index");
+        checkPathExists(indexed, "test", "other", "oak:index", "index2",
+                ":index");
+    }
+
+    private Set<String> find(Property2IndexLookup lookup, String name,
+            String value) {
+        NodeState system = root.getChildNode(JCR_SYSTEM);
+        NodeState types = system.getChildNode(JCR_NODE_TYPES);
+        NodeState type = types.getChildNode(NT_BASE);
+        SelectorImpl selector = new SelectorImpl(type, NT_BASE);
+        Filter filter = new FilterImpl(selector, "SELECT * FROM [nt:base]");
+        return Sets.newHashSet(lookup.query(filter, name,
+                PropertyValues.newString(value)));
+    }
+
+    private static NodeState checkPathExists(NodeState state, String... verify) {
+        NodeState c = state;
+        for (String p : verify) {
+            c = c.getChildNode(p);
+            assertTrue(c.exists());
+        }
+        return c;
+    }
+
+}
Index: src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java	(revision 1475687)
+++ src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java	(working copy)
@@ -1,253 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.oak.plugins.index;
-
-import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
-import static org.apache.jackrabbit.JcrConstants.NT_BASE;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
-import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
-import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
-import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Set;
-
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexHookProvider;
-import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexLookup;
-import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
-import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
-import org.apache.jackrabbit.oak.query.index.FilterImpl;
-import org.apache.jackrabbit.oak.spi.commit.EditorHook;
-import org.apache.jackrabbit.oak.spi.query.Filter;
-import org.apache.jackrabbit.oak.spi.query.PropertyValues;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-
-public class IndexHookManagerTest {
-
-    private NodeState root = new InitialContent().initialize(EMPTY_NODE);
-
-    private NodeBuilder builder = root.builder();
-
-    /**
-     * Simple Test
-     * <ul>
-     * <li>Add an index definition</li>
-     * <li>Add some content</li>
-     * <li>Search & verify</li>
-     * </ul>
-     * 
-     */
-    @Test
-    public void test() throws Exception {
-        createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
-                false, ImmutableSet.of("foo"), null);
-        createIndexDefinition(
-                builder.child("newchild").child("other").child("oak:index"),
-                "subIndex", true, false, ImmutableSet.of("foo"), null);
-
-        NodeState before = builder.getNodeState();
-
-        // Add nodes
-        builder.child("testRoot").setProperty("foo", "abc");
-        builder.child("newchild").child("other").child("testChild")
-                .setProperty("foo", "xyz");
-
-        NodeState after = builder.getNodeState();
-
-        IndexHookManager im = IndexHookManager
-                .of(new Property2IndexHookProvider());
-        EditorHook hook = new EditorHook(im);
-        NodeState indexed = hook.processCommit(before, after);
-
-        // first check that the index content nodes exist
-        checkPathExists(indexed, "oak:index", "rootIndex", ":index");
-        checkPathExists(indexed, "newchild", "other", "oak:index", "subIndex",
-                ":index");
-
-        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
-        assertEquals(ImmutableSet.of("testRoot"), find(lookup, "foo", "abc"));
-
-        Property2IndexLookup lookupChild = new Property2IndexLookup(indexed
-                .getChildNode("newchild").getChildNode("other"));
-        assertEquals(ImmutableSet.of("testChild"),
-                find(lookupChild, "foo", "xyz"));
-        assertEquals(ImmutableSet.of(), find(lookupChild, "foo", "abc"));
-
-    }
-
-    /**
-     * Reindex Test
-     * <ul>
-     * <li>Add some content</li>
-     * <li>Add an index definition with the reindex flag set</li>
-     * <li>Search & verify</li>
-     * </ul>
-     */
-    @Test
-    public void testReindex() throws Exception {
-        builder.child("testRoot").setProperty("foo", "abc");
-        NodeState before = builder.getNodeState();
-        createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
-                false, ImmutableSet.of("foo"), null);
-
-        NodeState after = builder.getNodeState();
-
-        IndexHookManager im = IndexHookManager
-                .of(new Property2IndexHookProvider());
-        EditorHook hook = new EditorHook(im);
-        NodeState indexed = hook.processCommit(before, after);
-
-        // first check that the index content nodes exist
-        NodeState ns = checkPathExists(indexed, "oak:index", "rootIndex");
-        checkPathExists(ns, ":index");
-        PropertyState ps = ns.getProperty(REINDEX_PROPERTY_NAME);
-        assertNotNull(ps);
-        assertFalse(ps.getValue(Type.BOOLEAN));
-
-        // next, lookup
-        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
-        assertEquals(ImmutableSet.of("testRoot"), find(lookup, "foo", "abc"));
-    }
-
-    /**
-     * Reindex Test
-     * <ul>
-     * <li>Add some content</li>
-     * <li>Add an index definition with no reindex flag</li>
-     * <li>Search & verify</li>
-     * </ul>
-     */
-    @Test
-    public void testReindex2() throws Exception {
-        builder.child("testRoot").setProperty("foo", "abc");
-        NodeState before = builder.getNodeState();
-
-        createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
-                false, ImmutableSet.of("foo"), null).removeProperty("reindex");
-
-        NodeState after = builder.getNodeState();
-
-        IndexHookManager im = IndexHookManager
-                .of(new Property2IndexHookProvider());
-        EditorHook hook = new EditorHook(im);
-        NodeState indexed = hook.processCommit(before, after);
-
-        // first check that the index content nodes exist
-        NodeState ns = checkPathExists(indexed, "oak:index", "rootIndex");
-        checkPathExists(ns, ":index");
-        PropertyState ps = ns.getProperty(REINDEX_PROPERTY_NAME);
-        assertNotNull(ps);
-        assertFalse(ps.getValue(Type.BOOLEAN));
-
-        // next, lookup
-        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
-        assertEquals(ImmutableSet.of("testRoot"), find(lookup, "foo", "abc"));
-    }
-
-    /**
-     * Reindex Test
-     * <ul>
-     * <li>Add some content & an index definition</li>
-     * <li>Update the index def by setting the reindex flag to true</li>
-     * <li>Search & verify</li>
-     * </ul>
-     */
-    @Test
-    public void testReindex3() throws Exception {
-        builder.child("testRoot").setProperty("foo", "abc");
-
-        createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
-                false, ImmutableSet.of("foo"), null).removeProperty("reindex");
-
-        NodeState before = builder.getNodeState();
-        builder.child("oak:index").child("rootIndex")
-                .setProperty(REINDEX_PROPERTY_NAME, true);
-        NodeState after = builder.getNodeState();
-
-        IndexHookManager im = IndexHookManager
-                .of(new Property2IndexHookProvider());
-        EditorHook hook = new EditorHook(im);
-        NodeState indexed = hook.processCommit(before, after);
-
-        // first check that the index content nodes exist
-        NodeState ns = checkPathExists(indexed, "oak:index", "rootIndex");
-        checkPathExists(ns, ":index");
-        PropertyState ps = ns.getProperty(REINDEX_PROPERTY_NAME);
-        assertNotNull(ps);
-        assertFalse(ps.getValue(Type.BOOLEAN));
-
-        // next, lookup
-        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
-        assertEquals(ImmutableSet.of("testRoot"), find(lookup, "foo", "abc"));
-    }
-
-    @Test
-    public void testIndexDefinitions() throws Exception {
-        createIndexDefinition(builder.child("oak:index"), "existing", true,
-                false, ImmutableSet.of("foo"), null);
-
-        NodeState before = builder.getNodeState();
-        // Add index definition
-        createIndexDefinition(builder.child("oak:index"), "foo", true, false,
-                ImmutableSet.of("foo"), null);
-        createIndexDefinition(
-                builder.child("test").child("other").child("oak:index"),
-                "index2", true, false, ImmutableSet.of("foo"), null);
-        NodeState after = builder.getNodeState();
-
-        IndexHookManager im = IndexHookManager
-                .of(new Property2IndexHookProvider());
-        EditorHook hook = new EditorHook(im);
-        NodeState indexed = hook.processCommit(before, after);
-
-        // check that the index content nodes exist
-        checkPathExists(indexed, "oak:index", "existing", ":index");
-        checkPathExists(indexed, "test", "other", "oak:index", "index2",
-                ":index");
-    }
-
-    private Set<String> find(Property2IndexLookup lookup, String name,
-            String value) {
-        NodeState system = root.getChildNode(JCR_SYSTEM);
-        NodeState types = system.getChildNode(JCR_NODE_TYPES);
-        NodeState type = types.getChildNode(NT_BASE);
-        SelectorImpl selector = new SelectorImpl(type, NT_BASE);
-        Filter filter = new FilterImpl(selector, "SELECT * FROM [nt:base]");
-        return Sets.newHashSet(lookup.query(filter, name,
-                PropertyValues.newString(value)));
-    }
-
-    private static NodeState checkPathExists(NodeState state, String... verify) {
-        NodeState c = state;
-        for (String p : verify) {
-            c = c.getChildNode(p);
-            assertTrue(c.exists());
-        }
-        return c;
-    }
-
-}
Index: src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java	(revision 1475687)
+++ src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java	(working copy)
@@ -75,7 +75,7 @@
         }
         NodeState after = builder.getNodeState();
 
-        EditorDiff.process(new Property2IndexHook(builder, after), before, after);
+        EditorDiff.process(new Property2IndexHook(builder), before, after);
         NodeState indexed = builder.getNodeState();
 
         FilterImpl f = createFilter(indexed, NT_BASE);
@@ -129,7 +129,7 @@
         NodeState after = builder.getNodeState();
 
         // Add an index
-        EditorDiff.process(new Property2IndexHook(builder, after), before, after);
+        EditorDiff.process(new Property2IndexHook(builder), before, after);
         NodeState indexed = builder.getNodeState();
 
         FilterImpl f = createFilter(indexed, NT_BASE);
@@ -190,7 +190,7 @@
                 .setProperty("foo", Arrays.asList("abc", "def"), Type.STRINGS);
         NodeState after = builder.getNodeState();
 
-        EditorDiff.process(new Property2IndexHook(builder, after), before, after);
+        EditorDiff.process(new Property2IndexHook(builder), before, after);
         NodeState indexed = builder.getNodeState();
 
         FilterImpl f = createFilter(indexed, "nt:unstructured");
@@ -256,7 +256,7 @@
         NodeState after = builder.getNodeState();
 
         // Add an index
-        EditorDiff.process(new Property2IndexHook(builder, after), before, after);
+        EditorDiff.process(new Property2IndexHook(builder), before, after);
         NodeState indexed = builder.getNodeState();
 
         FilterImpl f = createFilter(after, "nt:unstructured");
@@ -298,7 +298,7 @@
         NodeState after = builder.getNodeState();
 
         CommitFailedException expected =
-                EditorDiff.process(new Property2IndexHook(builder, after), before, after);
+                EditorDiff.process(new Property2IndexHook(builder), before, after);
         assertNotNull("Unique constraint should be respected", expected);
     }
 
@@ -327,7 +327,7 @@
         NodeState after = builder.getNodeState();
 
         CommitFailedException unexpected = EditorDiff.process(
-                new Property2IndexHook(builder, after), before, after);
+                new Property2IndexHook(builder), before, after);
         assertNull(unexpected);
     }
 
@@ -356,7 +356,7 @@
         NodeState after = builder.getNodeState();
 
         CommitFailedException expected = EditorDiff.process(
-                new Property2IndexHook(builder, after), before, after);
+                new Property2IndexHook(builder), before, after);
         assertNotNull("Unique constraint should be respected", expected);
     }
 
@@ -386,7 +386,7 @@
         NodeState after = builder.getNodeState();
 
         CommitFailedException unexpected = EditorDiff.process(
-                new Property2IndexHook(builder, after), before, after);
+                new Property2IndexHook(builder), before, after);
         assertNull(unexpected);
     }
 
Index: src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java	(revision 1475687)
+++ src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java	(working copy)
@@ -29,7 +29,7 @@
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
 import org.apache.jackrabbit.oak.plugins.index.CompositeIndexHookProvider;
-import org.apache.jackrabbit.oak.plugins.index.IndexHookManager;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.IndexHookProvider;
 import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexHookProvider;
 import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
@@ -79,8 +79,8 @@
         addFile(root, "file-1");
 
         branch.setRoot(root.getNodeState());
-        branch.merge(new EditorHook(IndexHookManager
-                .of(new Property2IndexHookProvider())));
+        branch.merge(new EditorHook(new IndexEditorProvider(
+                new Property2IndexHookProvider())));
 
         NodeState rootState = store.getRoot();
         NodeTypeIndex index = new NodeTypeIndex();
Index: src/main/java/org/apache/jackrabbit/oak/osgi/OsgiIndexHookProvider.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/osgi/OsgiIndexHookProvider.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/osgi/OsgiIndexHookProvider.java	(working copy)
@@ -18,15 +18,10 @@
  */
 package org.apache.jackrabbit.oak.osgi;
 
-import java.util.List;
-
-import javax.annotation.Nonnull;
-
 import org.apache.jackrabbit.oak.plugins.index.CompositeIndexHookProvider;
-import org.apache.jackrabbit.oak.plugins.index.IndexHook;
 import org.apache.jackrabbit.oak.plugins.index.IndexHookProvider;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * This IndexHook provider combines all index hooks of all available OSGi
@@ -40,11 +35,13 @@
     }
 
     @Override
-    @Nonnull
-    public List<? extends IndexHook> getIndexHooks(
-            String type, NodeBuilder builder, NodeState root) {
-        IndexHookProvider composite = CompositeIndexHookProvider.compose(getServices());
-        return composite.getIndexHooks(type, builder, root);
+    public Editor getIndexHook(String type, NodeBuilder builder) {
+        IndexHookProvider composite = CompositeIndexHookProvider
+                .compose(getServices());
+        if (composite == null) {
+            return null;
+        }
+        return composite.getIndexHook(type, builder);
     }
 
 }
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexHook.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexHook.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexHook.java	(working copy)
@@ -46,6 +46,7 @@
 import org.apache.jackrabbit.oak.plugins.index.IndexHook;
 import org.apache.jackrabbit.oak.plugins.index.p2.strategy.ContentMirrorStoreStrategy;
 import org.apache.jackrabbit.oak.plugins.index.p2.strategy.IndexStoreStrategy;
+import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -77,7 +78,7 @@
     private final Property2IndexHook parent;
 
     /**
-     * The node (never null).
+     * The node (can be null in the case of a deleted node).
      */
     private final NodeBuilder node;
 
@@ -101,36 +102,38 @@
     private final Map<String, List<Property2IndexHookUpdate>> indexMap;
 
     /**
-     * The root node state.
-     */
-    private final NodeState root;
-
-    /**
      * The {@code /jcr:system/jcr:nodeTypes} subtree.
      */
     private final NodeState types;
 
-    public Property2IndexHook(NodeBuilder builder, NodeState root) {
-        this(null, builder, null, "/",
-                new HashMap<String, List<Property2IndexHookUpdate>>(), root);
+    public Property2IndexHook(NodeBuilder builder) {
+        this(null, builder, null, "/");
     }
 
     private Property2IndexHook(Property2IndexHook parent, String nodeName) {
-        this(parent, getChildNode(parent.node, nodeName), nodeName, null,
-                parent.indexMap, parent.root);
+        this(parent, getChildNode(parent.node, nodeName), nodeName, null);
     }
 
     private Property2IndexHook(Property2IndexHook parent, NodeBuilder node,
-            String nodeName, String path,
-            Map<String, List<Property2IndexHookUpdate>> indexMap,
-            NodeState root) {
+            String nodeName, String path) {
         this.parent = parent;
         this.node = node;
         this.nodeName = nodeName;
         this.path = path;
-        this.indexMap = indexMap;
-        this.root = root;
-        this.types = root.getChildNode(JCR_SYSTEM).getChildNode(JCR_NODE_TYPES);
+
+        if (parent == null) {
+            this.indexMap = new HashMap<String, List<Property2IndexHookUpdate>>();
+            if (node.hasChildNode(JCR_SYSTEM)) {
+                NodeBuilder typeNB = node.getChildNode(JCR_SYSTEM)
+                        .getChildNode(JCR_NODE_TYPES);
+                this.types = typeNB.getNodeState();
+            } else {
+                this.types = EmptyNodeState.MISSING_NODE;
+            }
+        } else {
+            this.indexMap = parent.indexMap;
+            this.types = parent.types;
+        }
     }
 
     private static NodeBuilder getChildNode(NodeBuilder node, String name) {
@@ -297,22 +300,6 @@
         return childNodeChanged(name, before, EMPTY_NODE);
     }
 
-    @Override
-    public Editor reindex(NodeState state) {
-        boolean reindex = false;
-        for (List<Property2IndexHookUpdate> updateList : indexMap.values()) {
-            for (Property2IndexHookUpdate update : updateList) {
-                if (update.getAndResetReindexFlag()) {
-                    reindex = true;
-                }
-            }
-        }
-        if (reindex) {
-            return new Property2IndexHook(node, root);
-        }
-        return null;
-    }
-
     // -----------------------------------------------------< Closeable >--
 
     @Override
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexHookProvider.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexHookProvider.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexHookProvider.java	(working copy)
@@ -16,16 +16,11 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.p2;
 
-import java.util.List;
-
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.jackrabbit.oak.plugins.index.IndexHook;
 import org.apache.jackrabbit.oak.plugins.index.IndexHookProvider;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-
-import com.google.common.collect.ImmutableList;
 
 /**
  * Service that provides PropertyIndex based IndexHooks.
@@ -41,12 +36,11 @@
     public static final String TYPE = "p2";
 
     @Override
-    public List<? extends IndexHook> getIndexHooks(
-            String type, NodeBuilder builder, NodeState root) {
+    public Editor getIndexHook(String type, NodeBuilder builder) {
         if (TYPE.equals(type)) {
-            return ImmutableList.of(new Property2IndexHook(builder, root));
+            return new Property2IndexHook(builder);
         }
-        return ImmutableList.of();
+        return null;
     }
 
 }
\ No newline at end of file
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexHookUpdate.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexHookUpdate.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexHookUpdate.java	(working copy)
@@ -18,7 +18,6 @@
 
 import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.p2.Property2Index.encode;
 
 import java.util.Collections;
@@ -161,14 +160,6 @@
         return path;
     }
 
-    boolean getAndResetReindexFlag() {
-        PropertyState reindexPS = node.getProperty(REINDEX_PROPERTY_NAME);
-        boolean reindex = reindexPS == null
-                || (reindexPS != null && reindexPS.getValue(Type.BOOLEAN));
-        node.setProperty(REINDEX_PROPERTY_NAME, false);
-        return reindex;
-    }
-
     public boolean matches(
             String path, Set<String> primaryTypes, Set<String> mixinTypes) {
         if (this.primaryTypes == null) {
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHook.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHook.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHook.java	(working copy)
@@ -16,11 +16,7 @@
  */
 package org.apache.jackrabbit.oak.plugins.index;
 
-import javax.annotation.CheckForNull;
-
-import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * Represents the content of a QueryIndex as well as a mechanism for keeping
@@ -30,26 +26,4 @@
  */
 public interface IndexHook extends Editor {
 
-    /**
-     * Return an editor that can be used to recreate this index, or
-     * <code>null</code> if reindexing is not required or is taken care of by
-     * the impl directly using the provided state as a reference <br>
-     * <br>
-     * By providing an Editor an impl could help the IndexManager gain some
-     * performance on account of doing the reindexing in parallel for all
-     * indexers <br>
-     * <br>
-     * <i>Note:</i> All the existing IndexHook impls require a call to
-     * {@link #enter(NodeState, NodeState)} to build initial state before
-     * calling {@link #reindex(NodeState)}, this is enforced via the
-     * IndexManager.
-     * 
-     * @param state
-     *            state can be used to reindex inside the IndexHook directly,
-     *            instead of providing an Editor
-     * 
-     */
-    @CheckForNull
-    Editor reindex(NodeState state) throws CommitFailedException;
-
 }
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java	(working copy)
@@ -18,26 +18,14 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.nodetype;
 
-import java.util.Set;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeIterator;
-
 import org.apache.jackrabbit.JcrConstants;
-import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.core.ReadOnlyTree;
-import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
-import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
+import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexLookup;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Cursors;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
-import com.google.common.collect.Sets;
-
 /**
  * <code>NodeTypeIndex</code> implements a {@link QueryIndex} using
  * {@link Property2IndexLookup}s on <code>jcr:primaryType</code> and
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManager.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManager.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManager.java	(working copy)
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.oak.plugins.index;
-
-import org.apache.jackrabbit.oak.spi.commit.Editor;
-import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
-import org.apache.jackrabbit.oak.spi.commit.VisibleEditor;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-
-/**
- * Keeps existing IndexHooks updated. <br>
- * The existing index list is obtained via the IndexHookProvider.
- * 
- * @see IndexHook
- * @see IndexHookProvider
- * 
- */
-public class IndexHookManager implements EditorProvider {
-
-    public static final IndexHookManager of(IndexHookProvider provider) {
-        return new IndexHookManager(provider);
-    }
-
-    private final IndexHookProvider provider;
-
-    protected IndexHookManager(IndexHookProvider provider) {
-        this.provider = provider;
-    }
-
-    @Override
-    public Editor getRootEditor(NodeState before, NodeState after,
-            NodeBuilder builder) {
-        return VisibleEditor.wrap(new IndexHookManagerDiff(provider, builder, after));
-    }
-}
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexEditorProvider.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexEditorProvider.java	(revision 0)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexEditorProvider.java	(revision 0)
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index;
+
+import javax.annotation.CheckForNull;
+
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+public class IndexEditorProvider implements EditorProvider {
+
+    private final IndexHookProvider provider;
+
+    private final boolean async;
+
+    public IndexEditorProvider(IndexHookProvider provider) {
+        this(provider, false);
+    }
+
+    public IndexEditorProvider(IndexHookProvider provider, boolean async) {
+        this.provider = provider;
+        this.async = async;
+    }
+
+    @Override @CheckForNull
+    public Editor getRootEditor(
+            NodeState before, NodeState after, NodeBuilder builder) {
+        return new IndexEditor(provider, async, after, builder);
+    }
+
+}
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexEditor.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexEditor.java	(revision 0)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexEditor.java	(revision 0)
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Lists.newArrayListWithCapacity;
+import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.ASYNC_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.MISSING_NODE;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.spi.commit.CompositeEditor;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.EditorDiff;
+import org.apache.jackrabbit.oak.spi.commit.VisibleEditor;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+class IndexEditor implements Editor {
+
+    private final IndexHookProvider provider;
+
+    private final boolean async;
+
+    private final NodeState root;
+
+    private final NodeBuilder builder;
+
+    private final List<Editor> editors = newArrayList();
+
+    IndexEditor(
+            IndexHookProvider provider, boolean async,
+            NodeState root, NodeBuilder builder) {
+        this.provider = checkNotNull(provider);
+        this.async = async;
+        this.root = checkNotNull(root);
+        this.builder = checkNotNull(builder);
+    }
+
+    private IndexEditor(IndexEditor parent, String name) {
+        checkNotNull(parent);
+        this.provider = parent.provider;
+        this.async = parent.async;
+        this.root = parent.root;
+        this.builder = parent.builder.child(checkNotNull(name));
+    }
+
+    private static String getString(NodeBuilder builder, String name) {
+        PropertyState property = builder.getProperty(name);
+        if (property != null && property.getType() == STRING) {
+            return property.getValue(STRING);
+        } else {
+            return null;
+        }
+    }
+
+    private static boolean getBoolean(NodeBuilder builder, String name) {
+        PropertyState property = builder.getProperty(name);
+        return property != null
+                && property.getType() == BOOLEAN
+                && property.getValue(BOOLEAN);
+    }
+
+    @Override
+    public void enter(NodeState before, NodeState after)
+            throws CommitFailedException {
+        List<Editor> reindex = newArrayList();
+        if (builder.hasChildNode(INDEX_DEFINITIONS_NAME)) {
+            Map<String, Editor> tempEditors = new HashMap<String, Editor>();
+            NodeBuilder definitions = builder.child(INDEX_DEFINITIONS_NAME);
+            for (String name : definitions.getChildNodeNames()) {
+                NodeBuilder definition = definitions.child(name);
+                if (async == getBoolean(definition, ASYNC_PROPERTY_NAME)) {
+                    String type = getString(definition, TYPE_PROPERTY_NAME);
+                    Editor editor = null;
+                    if (tempEditors.containsKey(type)) {
+                        editor = tempEditors.get(type);
+                    } else {
+                        editor = provider.getIndexHook(type, builder);
+                        tempEditors.put(type, editor);
+                    }
+
+                    if (editor == null) {
+                        // trigger reindexing when an indexer becomes available
+                        definition.setProperty(REINDEX_PROPERTY_NAME, true);
+                    } else if (getBoolean(definition, REINDEX_PROPERTY_NAME)) {
+                        definition.setProperty(REINDEX_PROPERTY_NAME, false);
+                        definition.removeChildNode(":index");
+                        reindex.add(editor);
+                    } else {
+                        editors.add(VisibleEditor.wrap(editor));
+                    }
+                }
+            }
+        }
+
+        // no-op when reindex is empty
+        CommitFailedException exception = EditorDiff.process(
+                VisibleEditor.wrap(CompositeEditor.compose(reindex)), MISSING_NODE, after);
+        if (exception != null) {
+            throw exception;
+        }
+
+        for (Editor editor : editors) {
+            editor.enter(before, after);
+        }
+    }
+
+    @Override
+    public void leave(NodeState before, NodeState after)
+            throws CommitFailedException {
+        for (Editor editor : editors) {
+            editor.leave(before, after);
+        }
+    }
+
+    @Override
+    public void propertyAdded(PropertyState after)
+            throws CommitFailedException {
+        for (Editor editor : editors) {
+            editor.propertyAdded(after);
+        }
+    }
+
+    @Override
+    public void propertyChanged(PropertyState before, PropertyState after)
+            throws CommitFailedException {
+        for (Editor editor : editors) {
+            editor.propertyChanged(before, after);
+        }
+    }
+
+    @Override
+    public void propertyDeleted(PropertyState before)
+            throws CommitFailedException {
+        for (Editor editor : editors) {
+            editor.propertyDeleted(before);
+        }
+    }
+
+    @Override @Nonnull
+    public Editor childNodeAdded(String name, NodeState after)
+            throws CommitFailedException {
+        List<Editor> children = newArrayListWithCapacity(1 + editors.size());
+        children.add(new IndexEditor(this, name));
+        for (Editor editor : editors) {
+            Editor child = editor.childNodeAdded(name, after);
+            if (child != null) {
+                children.add(child);
+            }
+        }
+        return CompositeEditor.compose(children);
+    }
+
+    @Override @Nonnull
+    public Editor childNodeChanged(
+            String name, NodeState before, NodeState after)
+            throws CommitFailedException {
+        List<Editor> children = newArrayListWithCapacity(1 + editors.size());
+        children.add(new IndexEditor(this, name));
+        for (Editor editor : editors) {
+            Editor child = editor.childNodeChanged(name, before, after);
+            if (child != null) {
+                children.add(child);
+            }
+        }
+        return CompositeEditor.compose(children);
+    }
+
+    @Override @CheckForNull
+    public Editor childNodeDeleted(String name, NodeState before)
+            throws CommitFailedException {
+        List<Editor> children = newArrayListWithCapacity(editors.size());
+        for (Editor editor : editors) {
+            Editor child = editor.childNodeDeleted(name, before);
+            if (child != null) {
+                children.add(child);
+            }
+        }
+        return CompositeEditor.compose(children);
+    }
+
+}
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/CompositeIndexHookProvider.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/CompositeIndexHookProvider.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/CompositeIndexHookProvider.java	(working copy)
@@ -22,8 +22,10 @@
 
 import javax.annotation.Nonnull;
 
+import org.apache.jackrabbit.oak.spi.commit.CompositeEditor;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.VisibleEditor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -39,9 +41,8 @@
         if (providers.isEmpty()) {
             return new IndexHookProvider() {
                 @Override
-                public List<? extends IndexHook> getIndexHooks(
-                        String type, NodeBuilder builder, NodeState root) {
-                    return ImmutableList.of();
+                public Editor getIndexHook(String type, NodeBuilder builder) {
+                    return null;
                 }
             };
         } else if (providers.size() == 1) {
@@ -63,13 +64,14 @@
     }
 
     @Override
-    @Nonnull
-    public List<? extends IndexHook> getIndexHooks(
-            String type, NodeBuilder builder, NodeState root) {
-        List<IndexHook> indexes = Lists.newArrayList();
+    public Editor getIndexHook(String type, NodeBuilder builder) {
+        List<Editor> indexes = Lists.newArrayList();
         for (IndexHookProvider provider : providers) {
-            indexes.addAll(provider.getIndexHooks(type, builder, root));
+            Editor e = provider.getIndexHook(type, builder);
+            if (e != null) {
+                indexes.add(e);
+            }
         }
-        return indexes;
+        return VisibleEditor.wrap(CompositeEditor.compose(indexes));
     }
 }
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerDiff.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerDiff.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerDiff.java	(working copy)
@@ -1,189 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.oak.plugins.index;
-
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.ASYNC_PROPERTY_NAME;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
-import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.getBoolean;
-import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.isIndexNodeType;
-import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.spi.commit.CompositeEditor;
-import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
-import org.apache.jackrabbit.oak.spi.commit.Editor;
-import org.apache.jackrabbit.oak.spi.commit.EditorHook;
-import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
-import org.apache.jackrabbit.oak.spi.commit.VisibleEditor;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
-
-import com.google.common.collect.Lists;
-
-/**
- * Acts as a composite Editor, it delegates all the diff's events to the
- * existing IndexHooks. <br>
- * This allows for a simultaneous update of all the indexes via a single
- * traversal of the changes.
- */
-class IndexHookManagerDiff implements Editor {
-
-    private final IndexHookProvider provider;
-
-    private final NodeBuilder node;
-
-    private final NodeState root;
-
-    private Editor inner = new DefaultEditor();
-
-    public IndexHookManagerDiff(
-            IndexHookProvider provider, NodeBuilder node, NodeState root) {
-        this.provider = provider;
-        this.node = node;
-        this.root = root;
-    }
-
-    @Override
-    public void enter(NodeState before, NodeState after)
-            throws CommitFailedException {
-        NodeState ref = node.getNodeState();
-        if (!ref.hasChildNode(INDEX_DEFINITIONS_NAME)) {
-            return;
-        }
-
-        Set<String> allTypes = new HashSet<String>();
-        Set<String> reindexTypes = new HashSet<String>();
-        NodeState index = ref.getChildNode(INDEX_DEFINITIONS_NAME);
-        for (String indexName : index.getChildNodeNames()) {
-            NodeState indexChild = index.getChildNode(indexName);
-            if (isIndexNodeType(indexChild)) {
-                boolean reindex = getBoolean(indexChild, REINDEX_PROPERTY_NAME,
-                        true);
-                boolean async = getBoolean(indexChild, ASYNC_PROPERTY_NAME,
-                        false);
-                String type = null;
-                PropertyState typePS = indexChild
-                        .getProperty(TYPE_PROPERTY_NAME);
-                if (typePS != null && !typePS.isArray()) {
-                    type = typePS.getValue(Type.STRING);
-                }
-                if (type == null || async) {
-                    // skip null & async types
-                    continue;
-                }
-                if (reindex) {
-                    reindexTypes.add(type);
-                }
-                allTypes.add(type);
-            }
-        }
-
-        List<IndexHook> hooks = Lists.newArrayList();
-        List<IndexHook> reindex = Lists.newArrayList();
-        for (String type : allTypes) {
-            if (reindexTypes.contains(type)) {
-                reindex.addAll(provider.getIndexHooks(type, node, ref));
-            } else {
-                hooks.addAll(provider.getIndexHooks(type, node, ref));
-            }
-        }
-        reindex(reindex, ref);
-        if (!hooks.isEmpty()) {
-            this.inner = VisibleEditor.wrap(CompositeEditor.compose(hooks));
-            this.inner.enter(before, after);
-        }
-    }
-
-    private void reindex(List<IndexHook> hooks, NodeState state)
-            throws CommitFailedException {
-        if (hooks.isEmpty()) {
-            return;
-        }
-        List<Editor> editors = Lists.newArrayList();
-        for (IndexHook ih : hooks) {
-            ih.enter(EMPTY_NODE, state);
-            Editor e = ih.reindex(state);
-            if (e != null) {
-                editors.add(e);
-            }
-        }
-        final Editor reindexer = VisibleEditor.wrap(CompositeEditor
-                .compose(editors));
-        if (reindexer == null) {
-            return;
-        }
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return reindexer;
-            }
-        };
-        EditorHook eh = new EditorHook(provider);
-        eh.processCommit(EMPTY_NODE, state);
-    }
-
-    @Override
-    public void leave(NodeState before, NodeState after)
-            throws CommitFailedException {
-        this.inner.leave(before, after);
-    }
-
-    @Override
-    public void propertyAdded(PropertyState after) throws CommitFailedException {
-        inner.propertyAdded(after);
-    }
-
-    @Override
-    public void propertyChanged(PropertyState before, PropertyState after)
-            throws CommitFailedException {
-        inner.propertyChanged(before, after);
-    }
-
-    @Override
-    public void propertyDeleted(PropertyState before)
-            throws CommitFailedException {
-        inner.propertyDeleted(before);
-    }
-
-    @Override
-    public Editor childNodeAdded(String name, NodeState after)
-            throws CommitFailedException {
-        return inner.childNodeAdded(name, after);
-    }
-
-    @Override
-    public Editor childNodeChanged(String name, NodeState before,
-            NodeState after) throws CommitFailedException {
-        return inner.childNodeChanged(name, before, after);
-    }
-
-    @Override
-    public Editor childNodeDeleted(String name, NodeState before)
-            throws CommitFailedException {
-        return inner.childNodeDeleted(name, before);
-    }
-
-}
\ No newline at end of file
Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookProvider.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookProvider.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookProvider.java	(working copy)
@@ -16,12 +16,10 @@
  */
 package org.apache.jackrabbit.oak.plugins.index;
 
-import java.util.List;
-
-import javax.annotation.Nonnull;
+import javax.annotation.CheckForNull;
 
+import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * Extension point for plugging in different kinds of IndexHook providers.
@@ -34,26 +32,20 @@
      * 
      * Each provider knows how to produce a certain type of index. If the
      * <code>type</code> param is of an unknown value, the provider is expected
-     * to return an empty list.
+     * to return {@code null}.
      * 
      * <p>
-     * The <code>builder</code> must point to the repository content node, not
-     * the index content node. Each <code>IndexHook</code> implementation will
-     * have to drill down to its specific index content, and possibly deal with
-     * multiple indexes of the same type.
+     * The <code>builder</code> must points to the index definition node
+     * under which the indexer is expected to store the index content.
      * </p>
      * 
      * @param type
      *            the index type
      * @param builder
-     *            the node state builder of the content node that will be used
-     *            for updates
-     * @param root
-     *            root node state
-     * @return a list of index hooks of the given type
+     *            the node state builder of the index definition node that
+     *            will be used for updates
+     * @return index update editor, or {@code null} if type is unknown
      */
-    @Nonnull
-    List<? extends IndexHook> getIndexHooks(
-            String type, NodeBuilder builder, NodeState root);
-
+    @CheckForNull
+    Editor getIndexHook(String type, NodeBuilder builder);
 }
Index: src/main/java/org/apache/jackrabbit/oak/Oak.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/Oak.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/Oak.java	(working copy)
@@ -39,7 +39,7 @@
 import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
 import org.apache.jackrabbit.oak.plugins.commit.ConflictHook;
 import org.apache.jackrabbit.oak.plugins.index.CompositeIndexHookProvider;
-import org.apache.jackrabbit.oak.plugins.index.IndexHookManager;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.IndexHookProvider;
 import org.apache.jackrabbit.oak.plugins.observation2.EventQueueWriterProvider;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
@@ -267,7 +267,7 @@
                 CompositeHook.compose(initHooks));
 
         // add index hooks later to prevent the OakInitializer to do excessive indexing
-        with(IndexHookManager.of(indexHooks));
+        with(new IndexEditorProvider(indexHooks));
         with(new EventQueueWriterProvider());
         withEditorHook();
         CommitHook commitHook = CompositeHook.compose(commitHooks);
Index: src/main/java/org/apache/jackrabbit/oak/spi/lifecycle/OakInitializer.java
===================================================================
--- src/main/java/org/apache/jackrabbit/oak/spi/lifecycle/OakInitializer.java	(revision 1475687)
+++ src/main/java/org/apache/jackrabbit/oak/spi/lifecycle/OakInitializer.java	(working copy)
@@ -21,7 +21,7 @@
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.plugins.index.IndexHookManager;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.IndexHookProvider;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.EditorHook;
@@ -42,7 +42,7 @@
         NodeState before = branch.getHead();
         branch.setRoot(initializer.initialize(before));
         try {
-            branch.merge(new EditorHook(IndexHookManager.of(indexHook)));
+            branch.merge(new EditorHook(new IndexEditorProvider(indexHook)));
         } catch (CommitFailedException e) {
             throw new RuntimeException(e);
         }
@@ -61,7 +61,7 @@
         }
         branch.setRoot(root);
         try {
-            branch.merge(new EditorHook(IndexHookManager.of(indexHook)));
+            branch.merge(new EditorHook(new IndexEditorProvider(indexHook)));
         } catch (CommitFailedException e) {
             throw new RuntimeException(e);
         }
