You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by al...@apache.org on 2013/04/03 15:54:23 UTC

svn commit: r1464016 [1/2] - in /jackrabbit/oak/trunk: oak-core/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/ oak-core/src/main/java/org/apache/jackrabbit/oak/p...

Author: alexparvulescu
Date: Wed Apr  3 13:54:22 2013
New Revision: 1464016

URL: http://svn.apache.org/r1464016
Log:
OAK-734 Refactor indexing code to use Editors

Removed:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/HierarchicalNodeStateDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerDiffTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexQueryTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/pom.xml
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManager.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexDiff.java
    jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiff.java
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHook.java
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiffIT.java
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookIT.java
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java

Modified: jackrabbit/oak/trunk/oak-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/pom.xml?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-core/pom.xml Wed Apr  3 13:54:22 2013
@@ -54,7 +54,6 @@
               org.apache.jackrabbit.oak.plugins.commit,
               org.apache.jackrabbit.oak.plugins.index,
               org.apache.jackrabbit.oak.plugins.index.nodetype,
-              org.apache.jackrabbit.oak.plugins.index.property,
               org.apache.jackrabbit.oak.plugins.index.p2,
               org.apache.jackrabbit.oak.plugins.memory,
               org.apache.jackrabbit.oak.plugins.name,

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHook.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHook.java Wed Apr  3 13:54:22 2013
@@ -16,30 +16,25 @@
  */
 package org.apache.jackrabbit.oak.plugins.index;
 
-import java.io.Closeable;
-
 import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 
 /**
  * Represents the content of a QueryIndex as well as a mechanism for keeping
  * this content up to date.
- *<p>
+ * <p>
  * An IndexHook listens for changes to the content and updates the index data
  * accordingly.
  */
-public interface IndexHook extends HierarchicalNodeStateDiff<IndexHook>,
-        Closeable {
-
-    /**
-     * Applies the changes to the index content
-     */
-    void apply() throws CommitFailedException;
+public interface IndexHook extends Editor {
 
     /**
      * Re-create this index.
      * 
-     * @param state the parent of the node "oak:index" (the node that contains the index definition)
+     * @param state
+     *            the parent of the node "oak:index" (the node that contains the
+     *            index definition)
      * @throws CommitFailedException
      */
     void reindex(NodeBuilder state) throws CommitFailedException;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManager.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManager.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManager.java Wed Apr  3 13:54:22 2013
@@ -16,13 +16,9 @@
  */
 package org.apache.jackrabbit.oak.plugins.index;
 
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+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.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
@@ -37,56 +33,29 @@ import org.apache.jackrabbit.oak.spi.sta
  * @see IndexHookProvider
  * 
  */
-public class IndexHookManager implements CommitHook {
-
-    private final IndexHookProvider provider;
+public class IndexHookManager extends EditorHook {
 
     public static final IndexHookManager of(IndexHookProvider provider) {
-        return new IndexHookManager(provider);
+        return new IndexHookManager(new EditorProviderWrapper(provider));
     }
 
-    protected IndexHookManager(IndexHookProvider provider) {
-        this.provider = provider;
-    }
+    private static class EditorProviderWrapper implements EditorProvider {
 
-    @Override
-    public NodeState processCommit(NodeState before, NodeState after)
-            throws CommitFailedException {
-        NodeBuilder builder = after.builder();
-
-        // key: index type
-        // value: map of path to indexhook 
-        Map<String, Map<String, List<IndexHook>>> indexMap = new HashMap<String, Map<String, List<IndexHook>>>();
-        after.compareAgainstBaseState(before, new IndexHookManagerDiff(
-                provider, builder, indexMap));
-        apply(indexMap);
-        return builder.getNodeState();
-    }
+        private final IndexHookProvider provider;
 
-    private void apply(Map<String, Map<String, List<IndexHook>>> indexMap)
-            throws CommitFailedException {
-        try {
-            for (String type : indexMap.keySet()) {
-                for (List<IndexHook> hooks : indexMap.get(type).values()) {
-                    for (IndexHook hook : hooks) {
-                        hook.apply();
-                    }
-                }
-            }
-        } finally {
-            for (String type : indexMap.keySet()) {
-                for (List<IndexHook> hooks : indexMap.get(type).values()) {
-                    for (IndexHook hook : hooks) {
-                        try {
-                            hook.close();
-                        } catch (IOException e) {
-                            e.printStackTrace();
-                            throw new CommitFailedException(
-                                    "Failed to close the index hook", e);
-                        }
-                    }
-                }
-            }
+        EditorProviderWrapper(IndexHookProvider provider) {
+            this.provider = provider;
         }
+
+        @Override
+        public Editor getRootEditor(NodeState before, NodeState after,
+                NodeBuilder builder) {
+            return new IndexHookManagerDiff(provider, builder);
+        }
+
+    }
+
+    protected IndexHookManager(EditorProvider provider) {
+        super(provider);
     }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerDiff.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerDiff.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerDiff.java Wed Apr  3 13:54:22 2013
@@ -16,35 +16,28 @@
  */
 package org.apache.jackrabbit.oak.plugins.index;
 
-import java.util.ArrayList;
-import java.util.HashMap;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
+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.IndexConstants.TYPE_UNKNOWN;
+
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import java.util.TreeMap;
 
-import com.google.common.collect.Lists;
 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.commons.PathUtils;
+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.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
-import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
 import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
-import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
-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.IndexConstants.TYPE_UNKNOWN;
-import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import com.google.common.collect.Lists;
 
 /**
  * Acts as a composite NodeStateDiff, it delegates all the diff's events to the
@@ -53,79 +46,22 @@ import static org.apache.jackrabbit.oak.
  * This allows for a simultaneous update of all the indexes via a single
  * traversal of the changes.
  */
-class IndexHookManagerDiff implements NodeStateDiff {
-
-    private static final Logger LOG = LoggerFactory
-            .getLogger(IndexHookManagerDiff.class);
+class IndexHookManagerDiff implements Editor {
 
     private final IndexHookProvider provider;
 
-    private final IndexHookManagerDiff parent;
-
     private final NodeBuilder node;
 
-    private final String nodeName;
-
-    private String path;
-
-    /**
-     * The map of known indexes.
-     * 
-     * Key: index type name ("p2"). Value: a map from path to index hook.
-     */
-    private final Map<String, Map<String, List<IndexHook>>> indexMap;
+    private Editor inner = new DefaultEditor();
 
-    public IndexHookManagerDiff(IndexHookProvider provider, NodeBuilder root,
-            Map<String, Map<String, List<IndexHook>>> updates)
-            throws CommitFailedException {
-        this(provider, null, root, null, "/", updates);
-    }
-
-    private IndexHookManagerDiff(IndexHookProvider provider,
-            IndexHookManagerDiff parent, String nodeName)
-            throws CommitFailedException {
-        this(provider, parent, getChildNode(parent.node, nodeName), nodeName, null,
-                parent.indexMap);
-    }
-
-    private IndexHookManagerDiff(IndexHookProvider provider,
-            IndexHookManagerDiff parent, NodeBuilder node, String name,
-            String path, Map<String, Map<String, List<IndexHook>>> indexMap)
-            throws CommitFailedException {
+    public IndexHookManagerDiff(IndexHookProvider provider, NodeBuilder node) {
         this.provider = provider;
-        this.parent = parent;
         this.node = node;
-        this.nodeName = name;
-        this.path = path;
-        this.indexMap = indexMap;
-
-        if (node != null && isIndexNodeType(node.getProperty(JCR_PRIMARYTYPE))) {
-            // to prevent double-reindex we only call reindex if:
-            // - the flag exists and is set to true
-            // OR
-            // - the flag does not exist
-            boolean reindex = node.getProperty(REINDEX_PROPERTY_NAME) == null
-                    || node.getProperty(REINDEX_PROPERTY_NAME).getValue(
-                            Type.BOOLEAN);
-            if (reindex) {
-                node.setProperty(REINDEX_PROPERTY_NAME, true);
-                String type = TYPE_UNKNOWN;
-                PropertyState typePS = node.getProperty(TYPE_PROPERTY_NAME);
-                if (typePS != null && !typePS.isArray()) {
-                    type = typePS.getValue(Type.STRING);
-                }
-                // TODO this is kinda fragile
-                NodeBuilder rebuildBuilder = parent.parent.node;
-                String relativePath = PathUtils.getAncestorPath(getPath(), 2);
-                // find parent index by type and trigger a full reindex
-                List<IndexHook> indexes = getIndexesWithRelativePaths(
-                        relativePath, getIndexes(type));
-                for (IndexHook ih : indexes) {
-                    ih.reindex(rebuildBuilder);
-                }
-            }
-        }
+    }
 
+    @Override
+    public void enter(NodeState before, NodeState after)
+            throws CommitFailedException {
         if (node != null && node.hasChildNode(INDEX_DEFINITIONS_NAME)) {
             Set<String> existingTypes = new HashSet<String>();
             Set<String> reindexTypes = new HashSet<String>();
@@ -134,12 +70,12 @@ class IndexHookManagerDiff implements No
             for (String indexName : index.getChildNodeNames()) {
                 NodeBuilder indexChild = index.child(indexName);
                 if (isIndexNodeType(indexChild.getProperty(JCR_PRIMARYTYPE))) {
-                    // this reindex should only happen when the flag is set
-                    // before the index impl is online
-                    boolean reindex = indexChild
-                            .getProperty(REINDEX_PROPERTY_NAME) != null
-                            && indexChild.getProperty(REINDEX_PROPERTY_NAME)
-                                    .getValue(Type.BOOLEAN);
+                    PropertyState reindexPS = indexChild
+                            .getProperty(REINDEX_PROPERTY_NAME);
+                    boolean reindex = reindexPS == null
+                            || (reindexPS != null && indexChild.getProperty(
+                                    REINDEX_PROPERTY_NAME).getValue(
+                                    Type.BOOLEAN));
                     String type = TYPE_UNKNOWN;
                     PropertyState typePS = indexChild
                             .getProperty(TYPE_PROPERTY_NAME);
@@ -154,114 +90,31 @@ class IndexHookManagerDiff implements No
             }
             existingTypes.remove(TYPE_UNKNOWN);
             reindexTypes.remove(TYPE_UNKNOWN);
+
+            List<IndexHook> hooks = Lists.newArrayList();
+            List<IndexHook> reindex = Lists.newArrayList();
             for (String type : existingTypes) {
-                Map<String, List<IndexHook>> byType = this.indexMap.get(type);
-                if (byType == null) {
-                    byType = new TreeMap<String, List<IndexHook>>();
-                    this.indexMap.put(type, byType);
-                }
-                List<IndexHook> hooks = byType.get(getPath());
-                if (hooks == null) {
-                    hooks = Lists.newArrayList();
-                    byType.put(getPath(), hooks);
-                }
+                List<? extends IndexHook> hooksTmp = provider.getIndexHooks(
+                        type, node);
+                hooks.addAll(hooksTmp);
                 if (reindexTypes.contains(type)) {
-                    for (IndexHook ih : provider.getIndexHooks(type, node)) {
-                        ih.reindex(node);
-                        // TODO proper cleanup of resources in the case of an
-                        // exception?
-                        hooks.add(ih);
-                    }
-                } else {
-                    hooks.addAll(provider.getIndexHooks(type, node));
+                    reindex.addAll(hooksTmp);
                 }
             }
-        }
-    }
-
-    private static NodeBuilder getChildNode(NodeBuilder node, String nodeName) {
-        if (node != null && node.hasChildNode(nodeName)) {
-            return node.child(nodeName);
-        } else {
-            return null;
-        }
-    }
-
-    private String getPath() {
-        if (path == null) { 
-            // => parent != null
-            path = concat(parent.getPath(), nodeName);
-        }
-        return path;
-    }
-
-    /**
-     * Returns IndexHooks of all types that have the best match (are situated
-     * the closest on the hierarchy) for the given path.
-     */
-    private Map<String, List<IndexHook>> getIndexes() {
-        Map<String, List<IndexHook>> hooks = new HashMap<String, List<IndexHook>>();
-        for (String type : this.indexMap.keySet()) {
-            Map<String, List<IndexHook>> newIndexes = getIndexes(type);
-            for (String key : newIndexes.keySet()) {
-                if (hooks.containsKey(key)) {
-                    hooks.get(key).addAll(newIndexes.get(key));
-                } else {
-                    hooks.put(key, newIndexes.get(key));
+            if (!hooks.isEmpty()) {
+                this.inner = new CompositeEditor(hooks);
+                this.inner.enter(before, after);
+                for (IndexHook ih : reindex) {
+                    ih.reindex(node);
                 }
             }
         }
-        return hooks;
     }
 
-    /**
-     * Returns IndexHooks of the given type that have the best match (are
-     * situated the closest on the hierarchy) for the current path.
-     * 
-     * @param type the index type ("p2")
-     */
-    private Map<String, List<IndexHook>> getIndexes(String type) {
-        Map<String, List<IndexHook>> hooks = new HashMap<String, List<IndexHook>>();
-        Map<String, List<IndexHook>> indexes = this.indexMap.get(type);
-        if (indexes != null && !indexes.isEmpty()) {
-            Iterator<String> iterator = indexes.keySet().iterator();
-            String bestMatch = iterator.next();
-            while (iterator.hasNext()) {
-                String key = iterator.next();
-                if (PathUtils.isAncestor(key, getPath())) {
-                    bestMatch = key;
-                } else {
-                    break;
-                }
-            }
-            List<IndexHook> existing = hooks.get(bestMatch);
-            if (existing == null) {
-                existing = new ArrayList<IndexHook>();
-                hooks.put(bestMatch, existing);
-            }
-            existing.addAll(indexes.get(bestMatch));
-        }
-        return hooks;
-    }
-
-    /**
-     * Fixes the relative paths on the best matching indexes so updates apply
-     * properly
-     */
-    private static List<IndexHook> getIndexesWithRelativePaths(String path,
-            Map<String, List<IndexHook>> bestMatches) {
-        List<IndexHook> hooks = new ArrayList<IndexHook>();
-        for (String relativePath : bestMatches.keySet()) {
-            for (IndexHook update : bestMatches.get(relativePath)) {
-                IndexHook u = update;
-                String downPath = path.substring(relativePath.length());
-                for (String p : PathUtils.elements(downPath)) {
-                    u = u.child(p);
-                }
-                hooks.add(u);
-            }
-        }
-        return hooks;
+    @Override
+    public void leave(NodeState before, NodeState after)
+            throws CommitFailedException {
+        this.inner.leave(before, after);
     }
 
     private static boolean isIndexNodeType(PropertyState ps) {
@@ -269,55 +122,48 @@ class IndexHookManagerDiff implements No
                 && ps.getValue(Type.STRING).equals(INDEX_DEFINITIONS_NODE_TYPE);
     }
 
-    // -----------------------------------------------------< NodeStateDiff >---
-
     @Override
-    public void propertyAdded(PropertyState after) {
-        for (IndexHook update : getIndexesWithRelativePaths(getPath(),
-                getIndexes())) {
-            update.propertyAdded(after);
-        }
+    public void propertyAdded(PropertyState after) throws CommitFailedException {
+        inner.propertyAdded(after);
     }
 
     @Override
-    public void propertyChanged(PropertyState before, PropertyState after) {
-        for (IndexHook update : getIndexesWithRelativePaths(getPath(),
-                getIndexes())) {
-            update.propertyChanged(before, after);
-        }
+    public void propertyChanged(PropertyState before, PropertyState after)
+            throws CommitFailedException {
+        inner.propertyChanged(before, after);
     }
 
     @Override
-    public void propertyDeleted(PropertyState before) {
-        for (IndexHook update : getIndexesWithRelativePaths(getPath(),
-                getIndexes())) {
-            update.propertyDeleted(before);
-        }
+    public void propertyDeleted(PropertyState before)
+            throws CommitFailedException {
+        inner.propertyDeleted(before);
     }
 
     @Override
-    public void childNodeAdded(String nodeName, NodeState after) {
-        childNodeChanged(nodeName, EMPTY_NODE, after);
+    public Editor childNodeAdded(String name, NodeState after)
+            throws CommitFailedException {
+        if (NodeStateUtils.isHidden(name)) {
+            return null;
+        }
+        return inner.childNodeAdded(name, after);
     }
 
     @Override
-    public void childNodeChanged(String nodeName, NodeState before, NodeState after) {
-        if (NodeStateUtils.isHidden(nodeName)) {
-            return;
-        }
-        getIndexesWithRelativePaths(concat(getPath(), nodeName), getIndexes());
-
-        try {
-            after.compareAgainstBaseState(before, new IndexHookManagerDiff(
-                    provider, this, nodeName));
-        } catch (CommitFailedException e) {
-            // TODO ignore exception - is this a hack?
-            LOG.error(e.getMessage(), e);
+    public Editor childNodeChanged(String name, NodeState before,
+            NodeState after) throws CommitFailedException {
+        if (NodeStateUtils.isHidden(name)) {
+            return null;
         }
+        return inner.childNodeChanged(name, before, after);
     }
 
     @Override
-    public void childNodeDeleted(String nodeName, NodeState before) {
-        childNodeChanged(nodeName, before, EMPTY_NODE);
+    public Editor childNodeDeleted(String name, NodeState before)
+            throws CommitFailedException {
+        if (NodeStateUtils.isHidden(name)) {
+            return null;
+        }
+        return inner.childNodeDeleted(name, before);
     }
+
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java Wed Apr  3 13:54:22 2013
@@ -26,7 +26,7 @@ import org.apache.jackrabbit.oak.spi.sta
 import com.google.common.collect.Iterables;
 
 /**
- * <code>NodeTypeIndexLookup</code> uses {@link PropertyIndexLookup} internally
+ * <code>NodeTypeIndexLookup</code> uses {@link Property2IndexLookup} internally
  * for cost calculation and queries.
  */
 class NodeTypeIndexLookup implements JcrConstants {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexDiff.java Wed Apr  3 13:54:22 2013
@@ -16,6 +16,16 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.p2;
 
+import static com.google.common.collect.Lists.newArrayList;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.p2.Property2Index.TYPE;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+
+import java.io.Closeable;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -23,25 +33,20 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import com.google.common.collect.ImmutableList;
 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.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.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.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
 
-import static com.google.common.collect.Lists.newArrayList;
-import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
-import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
-import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
-import static org.apache.jackrabbit.oak.plugins.index.p2.Property2Index.TYPE;
-import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import com.google.common.collect.ImmutableList;
 
 /**
  * {@link IndexHook} implementation that is responsible for keeping the
@@ -49,17 +54,16 @@ import static org.apache.jackrabbit.oak.
  * <p/>
  * There is a tree of PropertyIndexDiff objects, each object represents the
  * changes at a given node.
- *
+ * 
  * @see Property2Index
  * @see Property2IndexLookup
  */
-class Property2IndexDiff implements IndexHook {
+class Property2IndexDiff implements IndexHook, Closeable {
 
     protected static String propertyNames = "propertyNames";
 
     protected static String declaringNodeTypes = "declaringNodeTypes";
 
-
     private final IndexStoreStrategy store = new ContentMirrorStoreStrategy();
 
     /**
@@ -83,41 +87,36 @@ class Property2IndexDiff implements Inde
     private String path;
 
     /**
-     * The map of known indexes.
-     * Key: the property name. Value: the list of indexes (it is possible to
-     * have multiple indexes for the same property name).
+     * The map of known indexes. Key: the property name. Value: the list of
+     * indexes (it is possible to have multiple indexes for the same property
+     * name).
      */
     private final Map<String, List<Property2IndexUpdate>> indexMap;
 
+    /**
+     * the root editor in charge of applying the updates
+     */
+    private final boolean isRoot;
+
     public Property2IndexDiff(NodeBuilder root) {
         this(null, root, null, "/",
-                new HashMap<String, List<Property2IndexUpdate>>());
+                new HashMap<String, List<Property2IndexUpdate>>(), true);
     }
 
     private Property2IndexDiff(Property2IndexDiff parent, String nodeName) {
-        this(parent, getChildNode(parent.node, nodeName),
-                nodeName, null, parent.indexMap);
+        this(parent, getChildNode(parent.node, nodeName), nodeName, null,
+                parent.indexMap, false);
     }
 
-    private Property2IndexDiff(
-            Property2IndexDiff parent,
-            NodeBuilder node, String nodeName, String path,
-            Map<String, List<Property2IndexUpdate>> indexMap) {
+    private Property2IndexDiff(Property2IndexDiff parent, NodeBuilder node,
+            String nodeName, String path,
+            Map<String, List<Property2IndexUpdate>> indexMap, boolean isRoot) {
         this.parent = parent;
         this.node = node;
         this.nodeName = nodeName;
         this.path = path;
         this.indexMap = indexMap;
-
-        if (node != null && node.hasChildNode(INDEX_DEFINITIONS_NAME)) {
-            NodeBuilder index = node.child(INDEX_DEFINITIONS_NAME);
-            for (String indexName : index.getChildNodeNames()) {
-                NodeBuilder child = index.child(indexName);
-                if (isIndexNode(child)) {
-                    addIndexes(child, indexName);
-                }
-            }
-        }
+        this.isRoot = isRoot;
     }
 
     private static NodeBuilder getChildNode(NodeBuilder node, String name) {
@@ -128,7 +127,6 @@ class Property2IndexDiff implements Inde
         }
     }
 
-    @Override
     public String getPath() {
         // build the path lazily
         if (path == null) {
@@ -139,8 +137,9 @@ class Property2IndexDiff implements Inde
 
     /**
      * Get all the indexes for the given property name.
-     *
-     * @param propertyName the property name
+     * 
+     * @param propertyName
+     *            the property name
      * @return the indexes
      */
     private Iterable<Property2IndexUpdate> getIndexes(String propertyName) {
@@ -171,10 +170,13 @@ class Property2IndexDiff implements Inde
     }
 
     /**
-     * Add the index definitions to the in-memory set of known index definitions.
+     * Add the index definitions to the in-memory set of known index
+     * definitions.
      * 
-     * @param builder the node builder that contains the index definition
-     * @param indexName the name of the index
+     * @param builder
+     *            the node builder that contains the index definition
+     * @param indexName
+     *            the name of the index
      */
     private void addIndexes(NodeBuilder builder, String indexName) {
         List<String> typeNames = ImmutableList.of();
@@ -203,7 +205,8 @@ class Property2IndexDiff implements Inde
                 }
             }
             if (!exists) {
-                list.add(new Property2IndexUpdate(getPath(), builder, store, typeNames));
+                list.add(new Property2IndexUpdate(getPath(), builder, store,
+                        typeNames));
             }
         }
     }
@@ -221,7 +224,32 @@ class Property2IndexDiff implements Inde
         return isIndexType;
     }
 
-    //-----------------------------------------------------< NodeStateDiff >--
+    @Override
+    public void enter(NodeState before, NodeState after)
+            throws CommitFailedException {
+        if (node != null && node.hasChildNode(INDEX_DEFINITIONS_NAME)) {
+            NodeBuilder index = node.child(INDEX_DEFINITIONS_NAME);
+            for (String indexName : index.getChildNodeNames()) {
+                NodeBuilder child = index.child(indexName);
+                if (isIndexNode(child)) {
+                    addIndexes(child, indexName);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void leave(NodeState before, NodeState after)
+            throws CommitFailedException {
+        if (!isRoot) {
+            return;
+        }
+        for (List<Property2IndexUpdate> updateList : indexMap.values()) {
+            for (Property2IndexUpdate update : updateList) {
+                update.apply();
+            }
+        }
+    }
 
     @Override
     public void propertyAdded(PropertyState after) {
@@ -246,32 +274,24 @@ class Property2IndexDiff implements Inde
     }
 
     @Override
-    public void childNodeAdded(String name, NodeState after) {
-        childNodeChanged(name, EMPTY_NODE, after);
+    public Editor childNodeAdded(String name, NodeState after)
+            throws CommitFailedException {
+        return childNodeChanged(name, EMPTY_NODE, after);
     }
 
     @Override
-    public void childNodeChanged(
-            String name, NodeState before, NodeState after) {
-        if (!NodeStateUtils.isHidden(name)) {
-            after.compareAgainstBaseState(before, child(name));
+    public Editor childNodeChanged(String name, NodeState before,
+            NodeState after) throws CommitFailedException {
+        if (NodeStateUtils.isHidden(name)) {
+            return null;
         }
+        return new Property2IndexDiff(this, name);
     }
 
     @Override
-    public void childNodeDeleted(String name, NodeState before) {
-        childNodeChanged(name, before, EMPTY_NODE);
-    }
-
-    // -----------------------------------------------------< IndexHook >--
-
-    @Override
-    public void apply() throws CommitFailedException {
-        for (List<Property2IndexUpdate> updateList : indexMap.values()) {
-            for (Property2IndexUpdate update : updateList) {
-                update.apply();
-            }
-        }
+    public Editor childNodeDeleted(String name, NodeState before)
+            throws CommitFailedException {
+        return childNodeChanged(name, before, EMPTY_NODE);
     }
 
     @Override
@@ -285,16 +305,19 @@ class Property2IndexDiff implements Inde
             }
         }
         if (reindex) {
-            state.getNodeState().compareAgainstBaseState(
-                    EMPTY_NODE,
-                    new Property2IndexDiff(null, state, null, "/", indexMap));
+            EditorProvider provider = new EditorProvider() {
+                @Override
+                public Editor getRootEditor(NodeState before, NodeState after,
+                        NodeBuilder builder) {
+                    return new Property2IndexDiff(node);
+                }
+            };
+            EditorHook eh = new EditorHook(provider);
+            eh.processCommit(EMPTY_NODE, state.getNodeState());
         }
     }
 
-    @Override
-    public IndexHook child(String name) {
-        return new Property2IndexDiff(this, name);
-    }
+    // -----------------------------------------------------< Closeable >--
 
     @Override
     public void close() throws IOException {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexUpdate.java Wed Apr  3 13:54:22 2013
@@ -102,8 +102,10 @@ class Property2IndexUpdate {
     /**
      * A property value was added at the given path.
      * 
-     * @param path the path
-     * @param value the value
+     * @param path
+     *            the path
+     * @param value
+     *            the value
      */
     public void insert(String path, PropertyState value) {
         Preconditions.checkArgument(path.startsWith(this.path));
@@ -113,8 +115,10 @@ class Property2IndexUpdate {
     /**
      * A property value was removed at the given path.
      * 
-     * @param path the path
-     * @param value the value
+     * @param path
+     *            the path
+     * @param value
+     *            the value
      */
     public void remove(String path, PropertyState value) {
         Preconditions.checkArgument(path.startsWith(this.path));
@@ -141,9 +145,9 @@ class Property2IndexUpdate {
     }
 
     boolean getAndResetReindexFlag() {
-        boolean reindex = node.getProperty(REINDEX_PROPERTY_NAME) != null
-                && node.getProperty(REINDEX_PROPERTY_NAME).getValue(
-                        Type.BOOLEAN);
+        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;
     }
@@ -151,7 +155,8 @@ class Property2IndexUpdate {
     /**
      * Try to apply the changes to the index content (to the ":index" node.
      * 
-     * @throws CommitFailedException if a unique index was violated
+     * @throws CommitFailedException
+     *             if a unique index was violated
      */
     public void apply() throws CommitFailedException {
         boolean unique = node.getProperty("unique") != null

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java Wed Apr  3 13:54:22 2013
@@ -31,6 +31,9 @@ import org.apache.jackrabbit.oak.api.Pro
 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.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.query.PropertyValues;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -79,8 +82,8 @@ public class IndexHookManagerTest {
 
         NodeState after = builder.getNodeState();
 
-        IndexHookManager im = new IndexHookManager(
-                new CompositeIndexHookProvider(new Property2IndexHookProvider()));
+        IndexHookManager im = IndexHookManager
+                .of(new Property2IndexHookProvider());
         NodeState indexed = im.processCommit(before, after);
 
         // first check that the index content nodes exist
@@ -98,9 +101,11 @@ public class IndexHookManagerTest {
         assertEquals(ImmutableSet.of(), find(lookupChild, "foo", "abc"));
 
     }
-    
-    private static Set<String> find(Property2IndexLookup lookup, String name, String value) {
-        return Sets.newHashSet(lookup.query(null, name, PropertyValues.newString(value)));
+
+    private static Set<String> find(Property2IndexLookup lookup, String name,
+            String value) {
+        return Sets.newHashSet(lookup.query(null, name,
+                PropertyValues.newString(value)));
     }
 
     /**
@@ -129,8 +134,8 @@ public class IndexHookManagerTest {
                         Type.NAME);
         NodeState after = builder.getNodeState();
 
-        IndexHookManager im = new IndexHookManager(
-                new CompositeIndexHookProvider(new Property2IndexHookProvider()));
+        IndexHookManager im = IndexHookManager
+                .of(new Property2IndexHookProvider());
         NodeState indexed = im.processCommit(before, after);
 
         // first check that the index content nodes exist
@@ -170,8 +175,8 @@ public class IndexHookManagerTest {
                         Type.NAME);
         NodeState after = builder.getNodeState();
 
-        IndexHookManager im = new IndexHookManager(
-                new CompositeIndexHookProvider(new Property2IndexHookProvider()));
+        IndexHookManager im = IndexHookManager
+                .of(new Property2IndexHookProvider());
         NodeState indexed = im.processCommit(before, after);
 
         // first check that the index content nodes exist
@@ -212,8 +217,8 @@ public class IndexHookManagerTest {
                 .setProperty(REINDEX_PROPERTY_NAME, true);
         NodeState after = builder.getNodeState();
 
-        IndexHookManager im = new IndexHookManager(
-                new CompositeIndexHookProvider(new Property2IndexHookProvider()));
+        IndexHookManager im = IndexHookManager
+                .of(new Property2IndexHookProvider());
         NodeState indexed = im.processCommit(before, after);
 
         // first check that the index content nodes exist
@@ -228,6 +233,51 @@ public class IndexHookManagerTest {
         assertEquals(ImmutableSet.of("testRoot"), find(lookup, "foo", "abc"));
     }
 
+    @Test
+    public void testIndexDefinitions() throws Exception {
+        NodeState root = EMPTY_NODE;
+
+        NodeBuilder builder = root.builder();
+        // this index is on the current update branch, it should be seen by the
+        // diff
+        builder.child("oak:index")
+                .child("existing")
+                .setProperty("type", "p2")
+                .setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE,
+                        Type.NAME);
+
+        NodeState before = builder.getNodeState();
+        // Add index definition
+        builder.child("oak:index")
+                .child("foo")
+                .setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE,
+                        Type.NAME);
+        builder.child("test")
+                .child("other")
+                .child("oak:index")
+                .child("index2")
+                .setProperty("type", "p2")
+                .setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE,
+                        Type.NAME);
+        NodeState after = builder.getNodeState();
+
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new IndexHookManagerDiff(
+                        new Property2IndexHookProvider(), builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
+        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 static NodeState checkPathExists(NodeState state, String... verify) {
         NodeState c = state;
         for (String p : verify) {

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java Wed Apr  3 13:54:22 2013
@@ -26,8 +26,10 @@ import java.util.Set;
 
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.plugins.index.IndexHook;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
+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.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -50,30 +52,36 @@ public class Property2IndexTest {
 
         // Add index definition
         NodeBuilder builder = root.builder();
-        builder.child("oak:index").child("foo")
-                .setProperty("jcr:primaryType", "oak:queryIndexDefinition", Type.NAME)
-                .setProperty("type", "p2")
+        builder.child("oak:index")
+                .child("foo")
+                .setProperty("jcr:primaryType", "oak:queryIndexDefinition",
+                        Type.NAME).setProperty("type", "p2")
                 .setProperty("propertyNames", "foo");
         NodeState before = builder.getNodeState();
 
         // Add some content and process it through the property index hook
         builder = before.builder();
         builder.child("a").setProperty("foo", "abc");
-        builder.child("b").setProperty("foo", Arrays.asList("abc", "def"), Type.STRINGS);
+        builder.child("b").setProperty("foo", Arrays.asList("abc", "def"),
+                Type.STRINGS);
         // plus lots of dummy content to highlight the benefit of indexing
         for (int i = 0; i < MANY; i++) {
             builder.child("n" + i).setProperty("foo", "xyz");
         }
         NodeState after = builder.getNodeState();
 
-        // Add an index
-        IndexHook p = new Property2IndexDiff(builder);
-        after.compareAgainstBaseState(before, p);
-        p.apply();
-        p.close();
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new Property2IndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
+        NodeState indexed = hook.processCommit(before, after);
 
         // Query the index
-        Property2IndexLookup lookup = new Property2IndexLookup(builder.getNodeState());
+        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
         assertEquals(ImmutableSet.of("a", "b"), find(lookup, "foo", "abc"));
         assertEquals(ImmutableSet.of("b"), find(lookup, "foo", "def"));
         assertEquals(ImmutableSet.of(), find(lookup, "foo", "ghi"));
@@ -87,11 +95,14 @@ public class Property2IndexTest {
         assertTrue("cost: " + cost, cost >= MANY);
     }
 
-    private static Set<String> find(Property2IndexLookup lookup, String name, String value, Filter filter) {
-        return Sets.newHashSet(lookup.query(filter, name, value == null ? null : PropertyValues.newString(value)));
+    private static Set<String> find(Property2IndexLookup lookup, String name,
+            String value, Filter filter) {
+        return Sets.newHashSet(lookup.query(filter, name, value == null ? null
+                : PropertyValues.newString(value)));
     }
 
-    private static Set<String> find(Property2IndexLookup lookup, String name, String value) {
+    private static Set<String> find(Property2IndexLookup lookup, String name,
+            String value) {
         return find(lookup, name, value, null);
     }
 
@@ -101,16 +112,21 @@ public class Property2IndexTest {
 
         // Add index definition
         NodeBuilder builder = root.builder();
-        builder.child("oak:index").child("fooIndex")
-                .setProperty("jcr:primaryType", "oak:queryIndexDefinition", Type.NAME)
+        builder.child("oak:index")
+                .child("fooIndex")
+                .setProperty("jcr:primaryType", "oak:queryIndexDefinition",
+                        Type.NAME)
                 .setProperty("type", "p2")
-                .setProperty("propertyNames", Arrays.asList("foo", "extrafoo"), Type.STRINGS);
+                .setProperty("propertyNames", Arrays.asList("foo", "extrafoo"),
+                        Type.STRINGS);
         NodeState before = builder.getNodeState();
 
         // Add some content and process it through the property index hook
         builder = before.builder();
-        builder.child("a").setProperty("foo", "abc").setProperty("extrafoo", "pqr");
-        builder.child("b").setProperty("foo", Arrays.asList("abc", "def"), Type.STRINGS);
+        builder.child("a").setProperty("foo", "abc")
+                .setProperty("extrafoo", "pqr");
+        builder.child("b").setProperty("foo", Arrays.asList("abc", "def"),
+                Type.STRINGS);
         // plus lots of dummy content to highlight the benefit of indexing
         for (int i = 0; i < MANY; i++) {
             builder.child("n" + i).setProperty("foo", "xyz");
@@ -118,19 +134,24 @@ public class Property2IndexTest {
         NodeState after = builder.getNodeState();
 
         // Add an index
-        IndexHook p = new Property2IndexDiff(builder);
-        after.compareAgainstBaseState(before, p);
-        p.apply();
-        p.close();
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new Property2IndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
+        NodeState indexed = hook.processCommit(before, after);
 
         // Query the index
-        Property2IndexLookup lookup = new Property2IndexLookup(builder.getNodeState());
+        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
         assertEquals(ImmutableSet.of("a", "b"), find(lookup, "foo", "abc"));
         assertEquals(ImmutableSet.of("b"), find(lookup, "foo", "def"));
         assertEquals(ImmutableSet.of(), find(lookup, "foo", "ghi"));
         assertEquals(MANY, find(lookup, "foo", "xyz").size());
         assertEquals(ImmutableSet.of("a"), find(lookup, "extrafoo", "pqr"));
-        
+
         try {
             assertEquals(ImmutableSet.of(), find(lookup, "pqr", "foo"));
             fail();
@@ -178,18 +199,21 @@ public class Property2IndexTest {
         NodeState after = builder.getNodeState();
 
         // Add an index
-        IndexHook p = new Property2IndexDiff(builder);
-        after.compareAgainstBaseState(before, p);
-        p.apply();
-        p.close();
-
-        NodeState indexedState = builder.getNodeState();
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new Property2IndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
+        NodeState indexed = hook.processCommit(before, after);
 
         FilterImpl f = new FilterImpl(null, null);
         f.setNodeType("nt:unstructured");
 
         // Query the index
-        Property2IndexLookup lookup = new Property2IndexLookup(indexedState);
+        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
         assertEquals(ImmutableSet.of("a", "b"), find(lookup, "foo", "abc", f));
         assertEquals(ImmutableSet.of("b"), find(lookup, "foo", "def", f));
         assertEquals(ImmutableSet.of(), find(lookup, "foo", "ghi", f));
@@ -239,18 +263,21 @@ public class Property2IndexTest {
         NodeState after = builder.getNodeState();
 
         // Add an index
-        IndexHook p = new Property2IndexDiff(builder);
-        after.compareAgainstBaseState(before, p);
-        p.apply();
-        p.close();
-
-        NodeState indexedState = builder.getNodeState();
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new Property2IndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
+        NodeState indexed = hook.processCommit(before, after);
 
         FilterImpl f = new FilterImpl(null, null);
         f.setNodeType("nt:unstructured");
 
         // Query the index
-        Property2IndexLookup lookup = new Property2IndexLookup(indexedState);
+        Property2IndexLookup lookup = new Property2IndexLookup(indexed);
         assertEquals(ImmutableSet.of("a", "b"), find(lookup, "foo", "abc", f));
         assertEquals(ImmutableSet.of("b"), find(lookup, "foo", "def", f));
         assertEquals(ImmutableSet.of(), find(lookup, "foo", "ghi", f));
@@ -285,15 +312,19 @@ public class Property2IndexTest {
                 Type.STRINGS);
         NodeState after = builder.getNodeState();
 
-        IndexHook p = new Property2IndexDiff(builder);
-        after.compareAgainstBaseState(before, p);
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new Property2IndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
         try {
-            p.apply();
+            hook.processCommit(before, after);
             fail("Unique constraint should be respected");
         } catch (CommitFailedException e) {
             // expected
-        } finally {
-            p.close();
         }
     }
 
@@ -303,26 +334,33 @@ public class Property2IndexTest {
 
         // Add index definition
         NodeBuilder builder = root.builder();
-        builder.child("oak:index").child("fooIndex")
-                .setProperty("jcr:primaryType", "oak:queryIndexDefinition", Type.NAME)
+        builder.child("oak:index")
+                .child("fooIndex")
+                .setProperty("jcr:primaryType", "oak:queryIndexDefinition",
+                        Type.NAME)
                 .setProperty("type", "p2")
                 .setProperty("unique", "true")
-                .setProperty("propertyNames", Arrays.asList("foo"), Type.STRINGS)
-                .setProperty(Property2IndexDiff.declaringNodeTypes, Arrays.asList("typeFoo"), Type.STRINGS);
+                .setProperty("propertyNames", Arrays.asList("foo"),
+                        Type.STRINGS)
+                .setProperty(Property2IndexDiff.declaringNodeTypes,
+                        Arrays.asList("typeFoo"), Type.STRINGS);
         NodeState before = builder.getNodeState();
         builder = before.builder();
-        builder.child("a")
-                .setProperty("jcr:primaryType", "typeFoo", Type.NAME)
+        builder.child("a").setProperty("jcr:primaryType", "typeFoo", Type.NAME)
                 .setProperty("foo", "abc");
-        builder.child("b")
-                .setProperty("jcr:primaryType", "typeBar", Type.NAME)
+        builder.child("b").setProperty("jcr:primaryType", "typeBar", Type.NAME)
                 .setProperty("foo", "abc");
         NodeState after = builder.getNodeState();
 
-        IndexHook p = new Property2IndexDiff(builder);
-        after.compareAgainstBaseState(before, p);
-        p.apply();
-        p.close();
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new Property2IndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
+        hook.processCommit(before, after);
     }
 
     @Test
@@ -331,31 +369,37 @@ public class Property2IndexTest {
 
         // Add index definition
         NodeBuilder builder = root.builder();
-        builder.child("oak:index").child("fooIndex")
-                .setProperty("jcr:primaryType", "oak:queryIndexDefinition", Type.NAME)
+        builder.child("oak:index")
+                .child("fooIndex")
+                .setProperty("jcr:primaryType", "oak:queryIndexDefinition",
+                        Type.NAME)
                 .setProperty("type", "p2")
                 .setProperty("unique", "true")
-                .setProperty("propertyNames", Arrays.asList("foo"), Type.STRINGS)
-                .setProperty(Property2IndexDiff.declaringNodeTypes, Arrays.asList("typeFoo"), Type.STRINGS);
+                .setProperty("propertyNames", Arrays.asList("foo"),
+                        Type.STRINGS)
+                .setProperty(Property2IndexDiff.declaringNodeTypes,
+                        Arrays.asList("typeFoo"), Type.STRINGS);
         NodeState before = builder.getNodeState();
         builder = before.builder();
-        builder.child("a")
-                .setProperty("jcr:primaryType", "typeFoo", Type.NAME)
+        builder.child("a").setProperty("jcr:primaryType", "typeFoo", Type.NAME)
                 .setProperty("foo", "abc");
-        builder.child("b")
-                .setProperty("jcr:primaryType", "typeFoo", Type.NAME)
+        builder.child("b").setProperty("jcr:primaryType", "typeFoo", Type.NAME)
                 .setProperty("foo", "abc");
         NodeState after = builder.getNodeState();
 
-        IndexHook p = new Property2IndexDiff(builder);
-        after.compareAgainstBaseState(before, p);
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new Property2IndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
         try {
-            p.apply();
+            hook.processCommit(before, after);
             fail("Unique constraint should be respected");
         } catch (CommitFailedException e) {
             // expected
-        } finally {
-            p.close();
         }
     }
 
@@ -365,27 +409,34 @@ public class Property2IndexTest {
 
         // Add index definition
         NodeBuilder builder = root.builder();
-        builder.child("oak:index").child("fooIndex")
-                .setProperty("jcr:primaryType", "oak:queryIndexDefinition", Type.NAME)
+        builder.child("oak:index")
+                .child("fooIndex")
+                .setProperty("jcr:primaryType", "oak:queryIndexDefinition",
+                        Type.NAME)
                 .setProperty("type", "p2")
                 .setProperty("unique", "true")
-                .setProperty("propertyNames", Arrays.asList("foo"), Type.STRINGS)
-                .setProperty(Property2IndexDiff.declaringNodeTypes, Arrays.asList("typeFoo"), Type.STRINGS);
-        builder.child("a")
-                .setProperty("jcr:primaryType", "typeFoo", Type.NAME)
+                .setProperty("propertyNames", Arrays.asList("foo"),
+                        Type.STRINGS)
+                .setProperty(Property2IndexDiff.declaringNodeTypes,
+                        Arrays.asList("typeFoo"), Type.STRINGS);
+        builder.child("a").setProperty("jcr:primaryType", "typeFoo", Type.NAME)
                 .setProperty("foo", "abc");
-        builder.child("b")
-                .setProperty("jcr:primaryType", "typeBar", Type.NAME)
+        builder.child("b").setProperty("jcr:primaryType", "typeBar", Type.NAME)
                 .setProperty("foo", "abc");
         NodeState before = builder.getNodeState();
         builder = before.builder();
         builder.removeNode("b");
         NodeState after = builder.getNodeState();
 
-        IndexHook p = new Property2IndexDiff(builder);
-        after.compareAgainstBaseState(before, p);
-        p.apply();
-        p.close();
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new Property2IndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
+        hook.processCommit(before, after);
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexDiff.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexDiff.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexDiff.java Wed Apr  3 13:54:22 2013
@@ -18,8 +18,13 @@ package org.apache.jackrabbit.oak.plugin
 
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
 import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.TYPE_LUCENE;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
@@ -28,6 +33,9 @@ import org.apache.jackrabbit.oak.api.Com
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.IndexHook;
+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.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
@@ -43,7 +51,7 @@ import org.apache.tika.parser.Parser;
  * @see LuceneIndex
  * 
  */
-public class LuceneIndexDiff implements IndexHook, LuceneIndexConstants {
+public class LuceneIndexDiff implements IndexHook, Closeable {
 
     private final LuceneIndexDiff parent;
 
@@ -55,41 +63,33 @@ public class LuceneIndexDiff implements 
 
     private final Map<String, LuceneIndexUpdate> updates;
 
+    /**
+     * the root editor in charge of applying the updates
+     */
+    private final boolean isRoot;
+
     private final Parser parser = new AutoDetectParser(
             TikaConfig.getDefaultConfig());
 
     private LuceneIndexDiff(LuceneIndexDiff parent, NodeBuilder node,
-            String name, String path, Map<String, LuceneIndexUpdate> updates) {
+            String name, String path, Map<String, LuceneIndexUpdate> updates,
+            boolean isRoot) {
         this.parent = parent;
         this.node = node;
         this.name = name;
         this.path = path;
         this.updates = updates;
-
-        if (node != null && node.hasChildNode(INDEX_DEFINITIONS_NAME)) {
-            NodeBuilder index = node.child(INDEX_DEFINITIONS_NAME);
-            for (String indexName : index.getChildNodeNames()) {
-                NodeBuilder child = index.child(indexName);
-                if (isIndexNode(child) && !this.updates.containsKey(getPath())) {
-                    this.updates.put(getPath(), new LuceneIndexUpdate(
-                            getPath(), child, parser));
-                }
-            }
-        }
-        if (node != null && name != null && !NodeStateUtils.isHidden(name)) {
-            for (LuceneIndexUpdate update : updates.values()) {
-                update.insert(getPath(), node);
-            }
-        }
+        this.isRoot = isRoot;
     }
 
     private LuceneIndexDiff(LuceneIndexDiff parent, String name) {
         this(parent, getChildNode(parent.node, name), name, null,
-                parent.updates);
+                parent.updates, false);
     }
 
     public LuceneIndexDiff(NodeBuilder root) {
-        this(null, root, null, "/", new HashMap<String, LuceneIndexUpdate>());
+        this(null, root, null, "/", new HashMap<String, LuceneIndexUpdate>(),
+                true);
     }
 
     private static NodeBuilder getChildNode(NodeBuilder node, String name) {
@@ -120,7 +120,36 @@ public class LuceneIndexDiff implements 
         return isIndexType;
     }
 
-    // -----------------------------------------------------< NodeStateDiff >--
+    @Override
+    public void enter(NodeState before, NodeState after)
+            throws CommitFailedException {
+        if (node != null && node.hasChildNode(INDEX_DEFINITIONS_NAME)) {
+            NodeBuilder index = node.child(INDEX_DEFINITIONS_NAME);
+            for (String indexName : index.getChildNodeNames()) {
+                NodeBuilder child = index.child(indexName);
+                if (isIndexNode(child) && !this.updates.containsKey(getPath())) {
+                    this.updates.put(getPath(), new LuceneIndexUpdate(
+                            getPath(), child, parser));
+                }
+            }
+        }
+        if (node != null && name != null && !NodeStateUtils.isHidden(name)) {
+            for (LuceneIndexUpdate update : updates.values()) {
+                update.insert(getPath(), node);
+            }
+        }
+    }
+
+    @Override
+    public void leave(NodeState before, NodeState after)
+            throws CommitFailedException {
+        if (!isRoot) {
+            return;
+        }
+        for (LuceneIndexUpdate update : updates.values()) {
+            update.apply();
+        }
+    }
 
     @Override
     public void propertyAdded(PropertyState after) {
@@ -144,41 +173,36 @@ public class LuceneIndexDiff implements 
     }
 
     @Override
-    public void childNodeAdded(String name, NodeState after) {
+    public Editor childNodeAdded(String name, NodeState after)
+            throws CommitFailedException {
         if (NodeStateUtils.isHidden(name)) {
-            return;
+            return null;
         }
         for (LuceneIndexUpdate update : updates.values()) {
             update.insert(concat(getPath(), name), new ReadOnlyBuilder(after));
         }
-        after.compareAgainstBaseState(EMPTY_NODE, child(name));
+        return childNodeChanged(name, EMPTY_NODE, after);
     }
 
     @Override
-    public void childNodeChanged(String name, NodeState before, NodeState after) {
+    public Editor childNodeChanged(String name, NodeState before,
+            NodeState after) throws CommitFailedException {
         if (NodeStateUtils.isHidden(name)) {
-            return;
+            return null;
         }
-        after.compareAgainstBaseState(before, child(name));
+        return new LuceneIndexDiff(this, name);
     }
 
     @Override
-    public void childNodeDeleted(String name, NodeState before) {
+    public Editor childNodeDeleted(String name, NodeState before)
+            throws CommitFailedException {
         if (NodeStateUtils.isHidden(name)) {
-            return;
+            return null;
         }
         for (LuceneIndexUpdate update : updates.values()) {
             update.remove(concat(getPath(), name));
         }
-    }
-
-    // -----------------------------------------------------< IndexHook >--
-
-    @Override
-    public void apply() throws CommitFailedException {
-        for (LuceneIndexUpdate update : updates.values()) {
-            update.apply();
-        }
+        return null;
     }
 
     @Override
@@ -190,16 +214,19 @@ public class LuceneIndexDiff implements 
             }
         }
         if (reindex) {
-            state.getNodeState().compareAgainstBaseState(
-                    EMPTY_NODE,
-                    new LuceneIndexDiff(null, state, null, "/", updates));
+            EditorProvider provider = new EditorProvider() {
+                @Override
+                public Editor getRootEditor(NodeState before, NodeState after,
+                        NodeBuilder builder) {
+                    return new LuceneIndexDiff(node);
+                }
+            };
+            EditorHook eh = new EditorHook(provider);
+            eh.processCommit(EMPTY_NODE, state.getNodeState());
         }
     }
 
-    @Override
-    public IndexHook child(String name) {
-        return new LuceneIndexDiff(this, name);
-    }
+    // -----------------------------------------------------< Closeable >--
 
     @Override
     public void close() throws IOException {

Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java Wed Apr  3 13:54:22 2013
@@ -24,9 +24,11 @@ import static org.apache.jackrabbit.oak.
 
 import org.apache.jackrabbit.oak.plugins.index.IndexDefinition;
 import org.apache.jackrabbit.oak.plugins.index.IndexDefinitionImpl;
-import org.apache.jackrabbit.oak.plugins.index.IndexHook;
 import org.apache.jackrabbit.oak.query.ast.Operator;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
+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.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
@@ -50,10 +52,15 @@ public class LuceneIndexTest implements 
         builder.setProperty("foo", "bar");
         NodeState after = builder.getNodeState();
 
-        IndexHook l = new LuceneIndexDiff(builder);
-        after.compareAgainstBaseState(before, l);
-        l.apply();
-        l.close();
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new LuceneIndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
+        NodeState indexed = hook.processCommit(before, after);
 
         IndexDefinition testDef = new IndexDefinitionImpl("lucene",
                 TYPE_LUCENE, "/oak:index/lucene");
@@ -62,7 +69,7 @@ public class LuceneIndexTest implements 
         filter.restrictPath("/", Filter.PathRestriction.EXACT);
         filter.restrictProperty("foo", Operator.EQUAL,
                 PropertyValues.newString("bar"));
-        Cursor cursor = queryIndex.query(filter, builder.getNodeState());
+        Cursor cursor = queryIndex.query(filter, indexed);
         assertTrue(cursor.hasNext());
         assertEquals("/", cursor.next().getPath());
         assertFalse(cursor.hasNext());
@@ -85,10 +92,15 @@ public class LuceneIndexTest implements 
 
         NodeState after = builder.getNodeState();
 
-        IndexHook l = new LuceneIndexDiff(builder);
-        after.compareAgainstBaseState(before, l);
-        l.apply();
-        l.close();
+        EditorProvider provider = new EditorProvider() {
+            @Override
+            public Editor getRootEditor(NodeState before, NodeState after,
+                    NodeBuilder builder) {
+                return new LuceneIndexDiff(builder);
+            }
+        };
+        EditorHook hook = new EditorHook(provider);
+        NodeState indexed = hook.processCommit(before, after);
 
         IndexDefinition testDef = new IndexDefinitionImpl("lucene",
                 TYPE_LUCENE, "/oak:index/lucene");
@@ -97,7 +109,7 @@ public class LuceneIndexTest implements 
         // filter.restrictPath("/", Filter.PathRestriction.EXACT);
         filter.restrictProperty("foo", Operator.EQUAL,
                 PropertyValues.newString("bar"));
-        Cursor cursor = queryIndex.query(filter, builder.getNodeState());
+        Cursor cursor = queryIndex.query(filter, indexed);
 
         assertTrue(cursor.hasNext());
         assertEquals("/", cursor.next().getPath());

Modified: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiff.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiff.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiff.java Wed Apr  3 13:54:22 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.solr.index;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
@@ -26,6 +27,9 @@ import org.apache.jackrabbit.oak.api.Typ
 import org.apache.jackrabbit.oak.plugins.index.IndexHook;
 import org.apache.jackrabbit.oak.plugins.index.solr.OakSolrConfiguration;
 import org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex;
+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.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
@@ -46,7 +50,7 @@ import static org.apache.jackrabbit.oak.
  * @see org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex
  * @see SolrIndexHook
  */
-public class SolrIndexDiff implements IndexHook {
+public class SolrIndexDiff implements IndexHook, Closeable {
 
     private final SolrIndexDiff parent;
 
@@ -62,8 +66,13 @@ public class SolrIndexDiff implements In
 
     private OakSolrConfiguration configuration;
 
+    /**
+     * the root editor in charge of applying the updates
+     */
+    private final boolean isRoot;
+
     private SolrIndexDiff(SolrIndexDiff parent, NodeBuilder node, SolrServer solrServer,
-                          String name, String path, Map<String, SolrIndexUpdate> updates, OakSolrConfiguration configuration) {
+                          String name, String path, Map<String, SolrIndexUpdate> updates, OakSolrConfiguration configuration, boolean isRoot) {
         this.parent = parent;
         this.node = node;
         this.name = name;
@@ -71,9 +80,22 @@ public class SolrIndexDiff implements In
         this.updates = updates;
         this.solrServer = solrServer;
         this.configuration = configuration;
+        this.isRoot = isRoot;
+    }
 
-        // TODO : test properly on PDFs
+    private SolrIndexDiff(SolrIndexDiff parent, SolrServer solrServer, String name) {
+        this(parent, getChildNode(parent.node, name), solrServer, name, null,
+                parent.updates, parent.configuration, false);
+    }
+
+    public SolrIndexDiff(NodeBuilder root, SolrServer solrServer, OakSolrConfiguration configuration) {
+        this(null, root, solrServer, null, "/", new HashMap<String, SolrIndexUpdate>(), configuration, true);
+    }
 
+    @Override
+    public void enter(NodeState before, NodeState after)
+            throws CommitFailedException {
+        // TODO : test properly on PDFs
         if (node != null && node.hasChildNode("oak:index")) {
             NodeBuilder index = node.child("oak:index");
             for (String indexName : index.getChildNodeNames()) {
@@ -91,15 +113,6 @@ public class SolrIndexDiff implements In
         }
     }
 
-    private SolrIndexDiff(SolrIndexDiff parent, SolrServer solrServer, String name) {
-        this(parent, getChildNode(parent.node, name), solrServer, name, null,
-                parent.updates, parent.configuration);
-    }
-
-    public SolrIndexDiff(NodeBuilder root, SolrServer solrServer, OakSolrConfiguration configuration) {
-        this(null, root, solrServer, null, "/", new HashMap<String, SolrIndexUpdate>(), configuration);
-    }
-
     private static NodeBuilder getChildNode(NodeBuilder node, String name) {
         if (node != null && node.hasChildNode(name)) {
             return node.child(name);
@@ -128,8 +141,6 @@ public class SolrIndexDiff implements In
         return isIndexType;
     }
 
-    // -----------------------------------------------------< NodeStateDiff >--
-
     @Override
     public void propertyAdded(PropertyState after) {
         for (SolrIndexUpdate update : updates.values()) {
@@ -152,38 +163,41 @@ public class SolrIndexDiff implements In
     }
 
     @Override
-    public void childNodeAdded(String name, NodeState after) {
+    public Editor childNodeAdded(String name, NodeState after) {
         if (NodeStateUtils.isHidden(name)) {
-            return;
+            return null;
         }
         for (SolrIndexUpdate update : updates.values()) {
             update.insert(concat(getPath(), name), new ReadOnlyBuilder(after));
         }
-        after.compareAgainstBaseState(EMPTY_NODE, child(name));
+        return childNodeChanged(name, EMPTY_NODE, after);
     }
 
     @Override
-    public void childNodeChanged(String name, NodeState before, NodeState after) {
+    public Editor childNodeChanged(String name, NodeState before, NodeState after) {
         if (NodeStateUtils.isHidden(name)) {
-            return;
+            return null;
         }
-        after.compareAgainstBaseState(before, child(name));
+        return new SolrIndexDiff(this, solrServer, name);
     }
 
     @Override
-    public void childNodeDeleted(String name, NodeState before) {
+    public Editor childNodeDeleted(String name, NodeState before) {
         if (NodeStateUtils.isHidden(name)) {
-            return;
+            return null;
         }
         for (SolrIndexUpdate update : updates.values()) {
             update.remove(concat(getPath(), name));
         }
+        return null;
     }
 
-    // -----------------------------------------------------< IndexHook >--
-
     @Override
-    public void apply() throws CommitFailedException {
+    public void leave(NodeState before, NodeState after)
+            throws CommitFailedException {
+        if(!isRoot){
+            return;
+        }
         for (SolrIndexUpdate update : updates.values()) {
             update.apply(solrServer);
         }
@@ -198,18 +212,19 @@ public class SolrIndexDiff implements In
             }
         }
         if (reindex) {
-            state.getNodeState().compareAgainstBaseState(
-                    EMPTY_NODE,
-                    new SolrIndexDiff(null, state, solrServer, null, "/", updates, configuration));
+            EditorProvider provider = new EditorProvider() {
+                @Override
+                public Editor getRootEditor(NodeState before, NodeState after,
+                        NodeBuilder builder) {
+                    return new SolrIndexDiff(node, solrServer, configuration);
+                }
+            };
+            EditorHook eh = new EditorHook(provider);
+            eh.processCommit(EMPTY_NODE, state.getNodeState());
         }
     }
 
     @Override
-    public IndexHook child(String name) {
-        return new SolrIndexDiff(this, solrServer, name);
-    }
-
-    @Override
     public void close() throws IOException {
         for (SolrIndexUpdate update : updates.values()) {
             update.close();

Modified: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHook.java?rev=1464016&r1=1464015&r2=1464016&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHook.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHook.java Wed Apr  3 13:54:22 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.solr.index;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.LinkedList;
@@ -26,6 +27,7 @@ import org.apache.jackrabbit.oak.api.Com
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.IndexHook;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -49,7 +51,7 @@ import org.slf4j.LoggerFactory;
  * @see org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex
  * @see SolrIndexDiff
  */
-public class SolrIndexHook implements IndexHook {
+public class SolrIndexHook implements IndexHook, Closeable {
 
     private static final Logger log = LoggerFactory.getLogger(SolrNodeStateDiff.class);
 
@@ -72,6 +74,10 @@ public class SolrIndexHook implements In
         this.deleteByIdQueryBuilder = initializeDeleteQueryBuilder();
     }
 
+    @Override
+    public void enter(NodeState before, NodeState after)
+            throws CommitFailedException {
+    }
 
     private Collection<SolrInputDocument> docsFromState(String path, @Nonnull NodeState state) {
         List<SolrInputDocument> solrInputDocuments = new LinkedList<SolrInputDocument>();
@@ -118,9 +124,9 @@ public class SolrIndexHook implements In
     }
 
     @Override
-    public void childNodeAdded(String name, NodeState after) {
+    public Editor childNodeAdded(String name, NodeState after) {
         if (NodeStateUtils.isHidden(name)) {
-            return;
+            return null;
         }
         if (exception == null) {
             try {
@@ -129,6 +135,7 @@ public class SolrIndexHook implements In
                 exception = e;
             }
         }
+        return null;
     }
 
     private void addSubtree(String name, NodeState nodeState) throws IOException {
@@ -136,26 +143,18 @@ public class SolrIndexHook implements In
     }
 
     @Override
-    public void childNodeChanged(String name, NodeState before, NodeState after) {
+    public Editor childNodeChanged(String name, NodeState before,
+            NodeState after) {
         if (NodeStateUtils.isHidden(name)) {
-            return;
-        }
-        if (exception == null) {
-            try {
-                SolrIndexHook diff = new SolrIndexHook(name, nodebuilder, solrServer);
-                after.compareAgainstBaseState(before, diff);
-                diff.apply();
-            } catch (CommitFailedException e) {
-                exception = new IOException(e);
-            }
-
+            return null;
         }
+        return new SolrIndexHook(name, nodebuilder, solrServer);
     }
 
     @Override
-    public void childNodeDeleted(String name, NodeState before) {
+    public Editor childNodeDeleted(String name, NodeState before) {
         if (NodeStateUtils.isHidden(name)) {
-            return;
+            return null;
         }
         if (exception == null) {
             try {
@@ -164,6 +163,7 @@ public class SolrIndexHook implements In
                 exception = e;
             }
         }
+        return null;
     }
 
     private void deleteSubtree(String name, NodeState before) throws IOException {
@@ -178,6 +178,18 @@ public class SolrIndexHook implements In
     }
 
     @Override
+    public void leave(NodeState before, NodeState after)
+            throws CommitFailedException {
+        if (exception == null) {
+            try {
+                apply();
+            } catch (CommitFailedException e) {
+                exception = new IOException(e);
+            }
+        }
+
+    }
+
     public void apply() throws CommitFailedException {
         try {
             if (exception != null) {
@@ -241,12 +253,6 @@ public class SolrIndexHook implements In
         deleteByIdQueryBuilder.delete(4, deleteByIdQueryBuilder.length());
     }
 
-    @Override
-    public IndexHook child(String name) {
-        return new SolrIndexHook(name, nodebuilder, solrServer);
-    }
-
-    @Override
     public String getPath() {
         return path;
     }