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 ju...@apache.org on 2013/06/11 15:00:06 UTC

svn commit: r1491780 [2/3] - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/ oak-core/src/main/java/org/apache/jackrabbit/oak/osgi/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/ oak-core/src/main/java/org/a...

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/PropertyIndexTest.java Tue Jun 11 13:00:04 2013
@@ -16,8 +16,6 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.property;
 
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
 import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
 import static org.apache.jackrabbit.JcrConstants.NT_BASE;
@@ -36,10 +34,11 @@ 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.IndexUpdateProvider;
 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.EditorDiff;
+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;
@@ -56,6 +55,9 @@ public class PropertyIndexTest {
 
     private static final int MANY = 100;
 
+    private static final EditorHook HOOK = new EditorHook(
+            new IndexUpdateProvider(new PropertyIndexEditorProvider()));
+
     @Test
     public void testPropertyLookup() throws Exception {
         NodeState root = new InitialContent().initialize(EMPTY_NODE);
@@ -67,7 +69,6 @@ public class PropertyIndexTest {
         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);
@@ -77,8 +78,7 @@ public class PropertyIndexTest {
         }
         NodeState after = builder.getNodeState();
 
-        EditorDiff.process(new PropertyIndexEditor(builder), before, after);
-        NodeState indexed = builder.getNodeState();
+        NodeState indexed = HOOK.processCommit(before, after);
 
         FilterImpl f = createFilter(indexed, NT_BASE);
 
@@ -115,7 +115,6 @@ public class PropertyIndexTest {
         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"),
@@ -127,8 +126,7 @@ public class PropertyIndexTest {
         NodeState after = builder.getNodeState();
 
         // Add an index
-        EditorDiff.process(new PropertyIndexEditor(builder), before, after);
-        NodeState indexed = builder.getNodeState();
+        NodeState indexed = HOOK.processCommit(before, after);
 
         FilterImpl f = createFilter(indexed, NT_BASE);
 
@@ -168,7 +166,6 @@ public class PropertyIndexTest {
         NodeState before = builder.getNodeState();
 
         // Add some content and process it through the property index hook
-        builder = before.builder();
         builder.child("a")
                 .setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED, Type.NAME)
                 .setProperty("foo", "abc");
@@ -177,8 +174,7 @@ public class PropertyIndexTest {
                 .setProperty("foo", Arrays.asList("abc", "def"), Type.STRINGS);
         NodeState after = builder.getNodeState();
 
-        EditorDiff.process(new PropertyIndexEditor(builder), before, after);
-        NodeState indexed = builder.getNodeState();
+        NodeState indexed = HOOK.processCommit(before, after);
 
         FilterImpl f = createFilter(indexed, NT_UNSTRUCTURED);
 
@@ -216,14 +212,15 @@ public class PropertyIndexTest {
         // Add index definitions
         NodeBuilder builder = root.builder();
         NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
-        createIndexDefinition(index, "fooIndex", true, false,
+        createIndexDefinition(
+                index, "fooIndex", true, false,
                 ImmutableSet.of("foo", "extrafoo"), null);
-        createIndexDefinition(index, "fooIndexFile", true, false,
+        createIndexDefinition(
+                index, "fooIndexFile", true, false,
                 ImmutableSet.of("foo"), ImmutableSet.of(NT_FILE));
         NodeState before = builder.getNodeState();
 
         // Add some content and process it through the property index hook
-        builder = before.builder();
         builder.child("a")
                 .setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED, Type.NAME)
                 .setProperty("foo", "abc");
@@ -233,8 +230,7 @@ public class PropertyIndexTest {
         NodeState after = builder.getNodeState();
 
         // Add an index
-        EditorDiff.process(new PropertyIndexEditor(builder), before, after);
-        NodeState indexed = builder.getNodeState();
+        NodeState indexed = HOOK.processCommit(before, after);
 
         FilterImpl f = createFilter(after, NT_UNSTRUCTURED);
 
@@ -252,24 +248,22 @@ public class PropertyIndexTest {
         }
     }
 
-    @Test
+    @Test(expected = CommitFailedException.class)
     public void testUnique() throws Exception {
         NodeState root = EMPTY_NODE;
 
         // Add index definition
         NodeBuilder builder = root.builder();
-        createIndexDefinition(builder.child(INDEX_DEFINITIONS_NAME),
+        createIndexDefinition(
+                builder.child(INDEX_DEFINITIONS_NAME),
                 "fooIndex", true, true, ImmutableSet.of("foo"), null);
         NodeState before = builder.getNodeState();
-        builder = before.builder();
         builder.child("a").setProperty("foo", "abc");
         builder.child("b").setProperty("foo", Arrays.asList("abc", "def"),
                 Type.STRINGS);
         NodeState after = builder.getNodeState();
 
-        CommitFailedException expected = EditorDiff.process(
-                new PropertyIndexEditor(builder), before, after);
-        assertNotNull("Unique constraint should be respected", expected);
+        HOOK.processCommit(before, after); // should throw
     }
 
     @Test
@@ -282,19 +276,16 @@ public class PropertyIndexTest {
                 "fooIndex", true, true, ImmutableSet.of("foo"),
                 ImmutableSet.of("typeFoo"));
         NodeState before = builder.getNodeState();
-        builder = before.builder();
         builder.child("a").setProperty(JCR_PRIMARYTYPE, "typeFoo", Type.NAME)
                 .setProperty("foo", "abc");
         builder.child("b").setProperty(JCR_PRIMARYTYPE, "typeBar", Type.NAME)
                 .setProperty("foo", "abc");
         NodeState after = builder.getNodeState();
 
-        CommitFailedException unexpected = EditorDiff.process(
-                new PropertyIndexEditor(builder), before, after);
-        assertNull(unexpected);
+        HOOK.processCommit(before, after); // should not throw
     }
 
-    @Test
+    @Test(expected = CommitFailedException.class)
     public void testUniqueByTypeKO() throws Exception {
         NodeState root = EMPTY_NODE;
 
@@ -304,16 +295,13 @@ public class PropertyIndexTest {
                 "fooIndex", true, true, ImmutableSet.of("foo"),
                 ImmutableSet.of("typeFoo"));
         NodeState before = builder.getNodeState();
-        builder = before.builder();
         builder.child("a").setProperty(JCR_PRIMARYTYPE, "typeFoo", Type.NAME)
                 .setProperty("foo", "abc");
         builder.child("b").setProperty(JCR_PRIMARYTYPE, "typeFoo", Type.NAME)
                 .setProperty("foo", "abc");
         NodeState after = builder.getNodeState();
 
-        CommitFailedException expected = EditorDiff.process(
-                new PropertyIndexEditor(builder), before, after);
-        assertNotNull("Unique constraint should be respected", expected);
+        HOOK.processCommit(before, after); // should throw
     }
 
     @Test
@@ -330,13 +318,10 @@ public class PropertyIndexTest {
         builder.child("b").setProperty(JCR_PRIMARYTYPE, "typeBar", Type.NAME)
                 .setProperty("foo", "abc");
         NodeState before = builder.getNodeState();
-        builder = before.builder();
         builder.getChildNode("b").remove();
         NodeState after = builder.getNodeState();
 
-        CommitFailedException unexpected = EditorDiff.process(
-                new PropertyIndexEditor(builder), before, after);
-        assertNull(unexpected);
+        HOOK.processCommit(before, after); // should not throw
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java Tue Jun 11 13:00:04 2013
@@ -16,9 +16,12 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.property.strategy;
 
+import static com.google.common.collect.Sets.newHashSet;
+import static java.util.Arrays.asList;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 
 import java.util.Collections;
+import java.util.Set;
 
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -29,10 +32,12 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.junit.Assert;
 import org.junit.Test;
 
-import com.google.common.collect.Sets;
-
 public class ContentMirrorStoreStrategyTest {
 
+    private static final Set<String> empty = newHashSet();
+
+    private static final Set<String> key = newHashSet("key");
+
     /**
      * <p>
      * Tests the index pruning mechanism
@@ -54,8 +59,9 @@ public class ContentMirrorStoreStrategyT
         NodeState root = EMPTY_NODE;
         NodeBuilder index = root.builder();
 
-        store.insert(index, "key",
-                Sets.newHashSet("/", "a/b/c", "a/b/d", "b", "d/e", "d/e/f"));
+        for (String path : asList("/", "a/b/c", "a/b/d", "b", "d/e", "d/e/f")) {
+            store.update(index, path, empty, key);
+        }
         checkPath(index, "key", "", true);
         checkPath(index, "key", "a/b/c", true);
         checkPath(index, "key", "a/b/d", true);
@@ -65,27 +71,30 @@ public class ContentMirrorStoreStrategyT
 
         // remove the root key, removes just the "match" property, when the
         // index is not empty
-        store.remove(index, "key", Sets.newHashSet("/"));
+        store.update(index, "/", key, empty);
         checkPath(index, "key", "d/e/f", true);
 
         // removing intermediary path doesn't remove the entire subtree
-        store.remove(index, "key", Sets.newHashSet("d/e"));
+        store.update(index, "d/e", key, empty);
         checkPath(index, "key", "d/e/f", true);
 
         // removing intermediary path doesn't remove the entire subtree
-        store.remove(index, "key", Sets.newHashSet("d/e/f"));
+        store.update(index, "d/e/f", key, empty);
         checkNotPath(index, "key", "d");
 
         // brother segment removed
-        store.remove(index, "key", Sets.newHashSet("a/b/d", "a/b"));
+        store.update(index, "a/b/d", key, empty);
+        store.update(index, "a/b", key, empty);
         checkPath(index, "key", "a/b/c", true);
 
         // reinsert root and remove everything else
-        store.insert(index, "key", Sets.newHashSet("/"));
-        store.remove(index, "key", Sets.newHashSet("d/e/f", "b", "a/b/c"));
+        store.update(index, "", empty, key);
+        store.update(index, "d/e/f", key, empty);
+        store.update(index, "b", key, empty);
+        store.update(index, "a/b/c", key, empty);
 
         // remove the root key when the index is empty
-        store.remove(index, "key", Sets.newHashSet("/"));
+        store.update(index, "", key, empty);
         Assert.assertEquals(0, index.getChildNodeCount());
     }
 
@@ -121,8 +130,8 @@ public class ContentMirrorStoreStrategyT
         IndexStoreStrategy store = new ContentMirrorStoreStrategy();
         NodeState root = EMPTY_NODE;
         NodeBuilder index = root.builder();
-        store.insert(index, "key", Sets.newHashSet("a"));
-        store.insert(index, "key", Sets.newHashSet("b"));
+        store.update(index, "a", empty, key);
+        store.update(index, "b", empty, key);
         Assert.assertTrue(
                 "ContentMirrorStoreStrategy should guarantee uniqueness on insert",
                 store.count(index.getNodeState(), Collections.singleton("key"), 2) > 1);

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java Tue Jun 11 13:00:04 2013
@@ -16,77 +16,150 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.lucene;
 
+import static org.apache.jackrabbit.JcrConstants.JCR_DATA;
 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.TYPE_PROPERTY_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.getString;
-import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.getChildOrNull;
-import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.TYPE_LUCENE;
-import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
-import static org.apache.jackrabbit.oak.spi.state.NodeStateUtils.isHidden;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.FieldFactory.newFulltextField;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.FieldFactory.newPathField;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.FieldFactory.newPropertyField;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.ANALYZER;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.INCLUDE_PROPERTY_TYPES;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.INDEX_DATA_CHILD_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.PERSISTENCE_PATH;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.TO_WRITE_LOCK_MS;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.VERSION;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.TermFactory.newPathTerm;
 
-import java.io.Closeable;
+import java.io.File;
 import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
+import java.io.InputStream;
 
+import javax.jcr.PropertyType;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.api.Blob;
 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.plugins.index.IndexEditor;
+import org.apache.jackrabbit.oak.plugins.index.lucene.aggregation.AggregatedState;
+import org.apache.jackrabbit.oak.plugins.index.lucene.aggregation.NodeAggregator;
 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.ReadOnlyBuilder;
-import org.apache.tika.config.TikaConfig;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.SerialMergeScheduler;
+import org.apache.lucene.search.PrefixQuery;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.tika.metadata.Metadata;
 import org.apache.tika.parser.AutoDetectParser;
+import org.apache.tika.parser.ParseContext;
 import org.apache.tika.parser.Parser;
+import org.apache.tika.sax.WriteOutContentHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * {@link IndexEditor} implementation that is responsible for keeping the
  * {@link LuceneIndex} up to date
  * 
  * @see LuceneIndex
- * 
  */
-public class LuceneIndexEditor implements IndexEditor, Closeable {
+public class LuceneIndexEditor implements IndexEditor {
 
-    private final LuceneIndexEditor parent;
+    private static final Logger log =
+            LoggerFactory.getLogger(LuceneIndexEditor.class);
+
+    private static final IndexWriterConfig config = getIndexWriterConfig();
+
+    private static final NodeAggregator aggregator = new NodeAggregator();
+
+    private static final Parser parser = new AutoDetectParser();
+
+    private static IndexWriterConfig getIndexWriterConfig() {
+        // FIXME: Hack needed to make Lucene work in an OSGi environment
+        Thread thread = Thread.currentThread();
+        ClassLoader loader = thread.getContextClassLoader();
+        thread.setContextClassLoader(IndexWriterConfig.class.getClassLoader());
+        try {
+            IndexWriterConfig config = new IndexWriterConfig(VERSION, ANALYZER);
+            config.setMergeScheduler(new SerialMergeScheduler());
+            config.setWriteLockTimeout(TO_WRITE_LOCK_MS);
+            return config;
+        } finally {
+            thread.setContextClassLoader(loader);
+        }
+    }
+
+    private static Directory newIndexDirectory(NodeBuilder definition)
+            throws CommitFailedException {
+        String path = getString(definition, PERSISTENCE_PATH);
+        if (path == null) {
+            return new ReadWriteOakDirectory(
+                    definition.child(INDEX_DATA_CHILD_NAME));
+        } else {
+            try {
+                File file = new File(path);
+                file.mkdirs();
+                return FSDirectory.open(file); // TODO: close() is never called
+            } catch (IOException e) {
+                throw new CommitFailedException(
+                        "Lucene", 1, "Failed to open the index in " + path, e);
+            }
+        }
+    }
 
-    private final NodeBuilder node;
+    /** Parent editor, or {@code null} if this is the root editor. */
+    private final LuceneIndexEditor parent;
 
+    /** Name of this node, or {@code null} for the root node. */
     private final String name;
 
+    /** Path of this editor, built lazily in {@link #getPath()}. */
     private String path;
 
-    private final Map<String, LuceneIndexUpdate> updates;
+    /** Index definition node builder */
+    private final NodeBuilder definition;
 
-    /**
-     * the root editor in charge of applying the updates
-     */
-    private final boolean isRoot;
-
-    private final Parser parser = new AutoDetectParser(
-            TikaConfig.getDefaultConfig());
-
-    private LuceneIndexEditor(LuceneIndexEditor parent, NodeBuilder node,
-            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;
-        this.isRoot = isRoot;
-    }
+    private final int propertyTypes;
 
-    private LuceneIndexEditor(LuceneIndexEditor parent, String name) {
-        this(parent, getChildOrNull(parent.node, name), name, null,
-                parent.updates, false);
+    private IndexWriter writer = null;
+
+    private boolean propertiesChanged = false;
+
+    LuceneIndexEditor(NodeBuilder definition) throws CommitFailedException {
+        this.parent = null;
+        this.name = null;
+        this.path = "/";
+        this.definition = definition;
+
+        PropertyState ps = definition.getProperty(INCLUDE_PROPERTY_TYPES);
+        if (ps != null) {
+            int types = 0;
+            for (String inc : ps.getValue(Type.STRINGS)) {
+                try {
+                    types |= 1 << PropertyType.valueFromName(inc);
+                } catch (IllegalArgumentException e) {
+                    log.warn("Unknown property type: " + inc);
+                }
+            }
+            this.propertyTypes = types;
+        } else {
+            this.propertyTypes = -1;
+        }
     }
 
-    public LuceneIndexEditor(NodeBuilder root) {
-        this(null, root, null, "/", new HashMap<String, LuceneIndexUpdate>(),
-                true);
+    private LuceneIndexEditor(LuceneIndexEditor parent, String name) {
+        this.parent = parent;
+        this.name = name;
+        this.path = null;
+        this.definition = parent.definition;
+        this.writer = parent.writer;
+        this.propertyTypes = parent.propertyTypes;
     }
 
     public String getPath() {
@@ -96,26 +169,15 @@ public class LuceneIndexEditor implement
         return path;
     }
 
-    private static boolean isIndexNode(NodeBuilder node) {
-        return TYPE_LUCENE.equals(getString(node, TYPE_PROPERTY_NAME));
-    }
-
     @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 && !isHidden(name)) {
-            for (LuceneIndexUpdate update : updates.values()) {
-                update.insert(getPath(), node);
+        if (parent == null) {
+            try {
+                writer = new IndexWriter(newIndexDirectory(definition), config);
+            } catch (IOException e) {
+                throw new CommitFailedException(
+                        "Lucene", 2, "Unable to create a new index writer", e);
             }
         }
     }
@@ -123,78 +185,158 @@ public class LuceneIndexEditor implement
     @Override
     public void leave(NodeState before, NodeState after)
             throws CommitFailedException {
-        if (!isRoot) {
-            return;
+        if (propertiesChanged || !before.exists()) {
+            String path = getPath();
+            try {
+                writer.updateDocument(
+                        newPathTerm(path), makeDocument(path, after));
+            } catch (IOException e) {
+                throw new CommitFailedException(
+                        "Lucene", 3, "Failed to index the node " + path, e);
+            }
         }
-        for (LuceneIndexUpdate update : updates.values()) {
-            update.apply();
+
+        if (parent == null) {
+            try {
+                writer.close();
+            } catch (IOException e) {
+                throw new CommitFailedException(
+                        "Lucene", 4, "Failed to close the Lucene index", e);
+            }
         }
-        updates.clear();
     }
 
     @Override
-    public void propertyAdded(PropertyState after) throws CommitFailedException {
-        for (LuceneIndexUpdate update : updates.values()) {
-            update.insert(getPath(), node);
-        }
+    public void propertyAdded(PropertyState after) {
+        propertiesChanged = true;
     }
 
     @Override
-    public void propertyChanged(PropertyState before, PropertyState after)
-            throws CommitFailedException {
-        for (LuceneIndexUpdate update : updates.values()) {
-            update.insert(getPath(), node);
-        }
+    public void propertyChanged(PropertyState before, PropertyState after) {
+        propertiesChanged = true;
     }
 
     @Override
-    public void propertyDeleted(PropertyState before)
-            throws CommitFailedException {
-        for (LuceneIndexUpdate update : updates.values()) {
-            update.insert(getPath(), node);
-        }
+    public void propertyDeleted(PropertyState before) {
+        propertiesChanged = true;
     }
 
     @Override
-    public Editor childNodeAdded(String name, NodeState after)
-            throws CommitFailedException {
-        if (isHidden(name)) {
-            return null;
-        }
-        for (LuceneIndexUpdate update : updates.values()) {
-            update.insert(concat(getPath(), name), new ReadOnlyBuilder(after));
-        }
-        return childNodeChanged(name, EMPTY_NODE, after);
+    public Editor childNodeAdded(String name, NodeState after) {
+        return new LuceneIndexEditor(this, name);
     }
 
     @Override
-    public Editor childNodeChanged(String name, NodeState before,
-            NodeState after) throws CommitFailedException {
-        if (isHidden(name)) {
-            return null;
-        }
+    public Editor childNodeChanged(
+            String name, NodeState before, NodeState after) {
         return new LuceneIndexEditor(this, name);
     }
 
     @Override
     public Editor childNodeDeleted(String name, NodeState before)
             throws CommitFailedException {
-        if (isHidden(name)) {
-            return null;
+        String path = PathUtils.concat(getPath(), name);
+
+        try {
+            // Remove all index entries in the removed subtree
+            writer.deleteDocuments(newPathTerm(path));
+            writer.deleteDocuments(new PrefixQuery(newPathTerm(path + "/")));
+        } catch (IOException e) {
+            throw new CommitFailedException(
+                    "Lucene", 5, "Failed to remove the index entries of"
+                    + " the removed subtree " + path, e);
+        }
+
+        return null; // no need to recurse down the removed subtree
+    }
+
+    private Document makeDocument(String path, NodeState state) {
+        Document document = new Document();
+        document.add(newPathField(path));
+
+        for (PropertyState property : state.getProperties()) {
+            String pname = property.getName();
+            if (isVisible(pname)
+                    && (propertyTypes & (1 << property.getType().tag())) != 0) {
+                if (Type.BINARY.tag() == property.getType().tag()) {
+                    addBinaryValue(document, property, state);
+                } else {
+                    for (String value : property.getValue(Type.STRINGS)) {
+                        document.add(newPropertyField(pname, value));
+                        document.add(newFulltextField(value));
+                    }
+                }
+            }
         }
-        for (LuceneIndexUpdate update : updates.values()) {
-            update.remove(concat(getPath(), name));
+
+        for (AggregatedState agg : aggregator.getAggregates(state)) {
+            for (PropertyState property : agg.getProperties()) {
+                String pname = property.getName();
+                if (isVisible(pname)
+                        && (propertyTypes & (1 << property.getType().tag())) != 0) {
+                    if (Type.BINARY.tag() == property.getType().tag()) {
+                        addBinaryValue(document, property, agg.get());
+                    } else {
+                        for (String v : property.getValue(Type.STRINGS)) {
+                            document.add(newFulltextField(v));
+                        }
+                    }
+                }
+            }
         }
-        return null;
+
+        return document;
     }
 
-    // -----------------------------------------------------< Closeable >--
+    private static boolean isVisible(String name) {
+        return name.charAt(0) != ':';
+    }
 
-    @Override
-    public void close() throws IOException {
-        for (LuceneIndexUpdate update : updates.values()) {
-            update.close();
+    private void addBinaryValue(
+            Document doc, PropertyState property, NodeState state) {
+        Metadata metadata = new Metadata();
+        if (JCR_DATA.equals(property.getName())) {
+            String type = getString(state, JcrConstants.JCR_MIMETYPE);
+            if (type != null) { // not mandatory
+                metadata.set(Metadata.CONTENT_TYPE, type);
+            }
+            String encoding = getString(state, JcrConstants.JCR_ENCODING);
+            if (encoding != null) { // not mandatory
+                metadata.set(Metadata.CONTENT_ENCODING, encoding);
+            }
         }
-        updates.clear();
+
+        for (Blob v : property.getValue(Type.BINARIES)) {
+            doc.add(newFulltextField(parseStringValue(v, metadata)));
+        }
+    }
+
+    private String parseStringValue(Blob v, Metadata metadata) {
+        WriteOutContentHandler handler = new WriteOutContentHandler();
+        try {
+            InputStream stream = v.getNewStream();
+            try {
+                parser.parse(stream, handler, metadata, new ParseContext());
+            } finally {
+                stream.close();
+            }
+        } catch (LinkageError e) {
+            // Capture and ignore errors caused by extraction libraries
+            // not being present. This is equivalent to disabling
+            // selected media types in configuration, so we can simply
+            // ignore these errors.
+        } catch (Throwable t) {
+            // Capture and report any other full text extraction problems.
+            // The special STOP exception is used for normal termination.
+            if (!handler.isWriteLimitReached(t)) {
+                log.debug("Failed to extract text from a binary property."
+                        + " This is a fairly common case, and nothing to"
+                        + " worry about. The stack trace is included to"
+                        + " help improve the text extraction feature.", t);
+                return "TextExtractionError";
+            }
+        }
+        return handler.toString();
     }
+
 }

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java Tue Jun 11 13:00:04 2013
@@ -20,10 +20,12 @@ import static org.apache.jackrabbit.oak.
 
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.plugins.index.IndexEditor;
 import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * Service that provides Lucene based {@link IndexEditor}s
@@ -37,9 +39,11 @@ import org.apache.jackrabbit.oak.spi.sta
 public class LuceneIndexEditorProvider implements IndexEditorProvider {
 
     @Override
-    public Editor getIndexEditor(String type, NodeBuilder builder) {
+    public Editor getIndexEditor(
+            String type, NodeBuilder definition, NodeState root)
+            throws CommitFailedException {
         if (TYPE_LUCENE.equals(type)) {
-            return new LuceneIndexEditor(builder);
+            return new LuceneIndexEditor(definition);
         }
         return null;
     }

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/aggregation/NodeAggregator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/aggregation/NodeAggregator.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/aggregation/NodeAggregator.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/aggregation/NodeAggregator.java Tue Jun 11 13:00:04 2013
@@ -23,19 +23,12 @@ import static org.apache.jackrabbit.oak.
 
 import java.util.List;
 
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 import com.google.common.collect.ImmutableList;
 
 public class NodeAggregator {
 
-    private final NodeBuilder index;
-
-    public NodeAggregator(NodeBuilder index) {
-        this.index = index;
-    }
-
     public List<AggregatedState> getAggregates(NodeState state) {
         // FIXME remove hardcoded aggregates
         String type = getString(state, JCR_PRIMARYTYPE);

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/LuceneIndexHelper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/LuceneIndexHelper.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/LuceneIndexHelper.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/LuceneIndexHelper.java Tue Jun 11 13:00:04 2013
@@ -50,12 +50,12 @@ public class LuceneIndexHelper {
     public static NodeBuilder newLuceneIndexDefinition(
             @Nonnull NodeBuilder index, @Nonnull String name,
             @Nullable Set<String> propertyTypes) {
-        return newLuceneIndexDefinition(index, name, propertyTypes, false);
+        return newLuceneIndexDefinition(index, name, propertyTypes, null);
     }
 
     public static NodeBuilder newLuceneIndexDefinition(
             @Nonnull NodeBuilder index, @Nonnull String name,
-            @Nullable Set<String> propertyTypes, boolean async) {
+            @Nullable Set<String> propertyTypes, String async) {
         if (index.hasChildNode(name)) {
             return index.child(name);
         }
@@ -63,8 +63,8 @@ public class LuceneIndexHelper {
         index.setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE, NAME)
                 .setProperty(TYPE_PROPERTY_NAME, TYPE_LUCENE)
                 .setProperty(REINDEX_PROPERTY_NAME, true);
-        if (async) {
-            index.setProperty(ASYNC_PROPERTY_NAME, true);
+        if (async != null) {
+            index.setProperty(ASYNC_PROPERTY_NAME, async);
         }
         if (propertyTypes != null && !propertyTypes.isEmpty()) {
             index.setProperty(PropertyStates.createProperty(
@@ -76,14 +76,14 @@ public class LuceneIndexHelper {
     public static NodeBuilder newLuceneFileIndexDefinition(
             @Nonnull NodeBuilder index, @Nonnull String name,
             @Nullable Set<String> propertyTypes, @Nonnull String path) {
-        return newLuceneFileIndexDefinition(index, name, propertyTypes, path,
-                false);
+        return newLuceneFileIndexDefinition(
+                index, name, propertyTypes, path, null);
     }
 
     public static NodeBuilder newLuceneFileIndexDefinition(
             @Nonnull NodeBuilder index, @Nonnull String name,
             @Nullable Set<String> propertyTypes, @Nonnull String path,
-            boolean async) {
+            String async) {
         if (index.hasChildNode(name)) {
             return index.child(name);
         }
@@ -93,8 +93,8 @@ public class LuceneIndexHelper {
                 .setProperty(PERSISTENCE_NAME, PERSISTENCE_FILE)
                 .setProperty(PERSISTENCE_PATH, path)
                 .setProperty(REINDEX_PROPERTY_NAME, true);
-        if (async) {
-            index.setProperty(ASYNC_PROPERTY_NAME, true);
+        if (async != null) {
+            index.setProperty(ASYNC_PROPERTY_NAME, async);
         }
         if (propertyTypes != null && !propertyTypes.isEmpty()) {
             index.setProperty(PropertyStates.createProperty(

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/LuceneInitializerHelper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/LuceneInitializerHelper.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/LuceneInitializerHelper.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/LuceneInitializerHelper.java Tue Jun 11 13:00:04 2013
@@ -34,7 +34,7 @@ public class LuceneInitializerHelper imp
 
     private final String filePath;
 
-    private boolean async = false;
+    private String async = null;
 
     public LuceneInitializerHelper(String name) {
         this(name, LuceneIndexHelper.JR_PROPERTY_INCLUDES);
@@ -52,7 +52,7 @@ public class LuceneInitializerHelper imp
     }
 
     public LuceneInitializerHelper async() {
-        async = true;
+        async = "async";
         return this;
     }
 

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=1491780&r1=1491779&r2=1491780&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 Tue Jun 11 13:00:04 2013
@@ -26,12 +26,15 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
 
+import javax.jcr.PropertyType;
+
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
 import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
 import org.apache.jackrabbit.oak.query.ast.Operator;
 import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
-import org.apache.jackrabbit.oak.spi.commit.EditorDiff;
+import org.apache.jackrabbit.oak.spi.commit.EditorHook;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
@@ -44,6 +47,9 @@ import com.google.common.collect.Immutab
 
 public class LuceneIndexTest {
 
+    private static final EditorHook HOOK = new EditorHook(
+            new IndexUpdateProvider(new LuceneIndexEditorProvider()));
+
     private NodeState root = new InitialContent().initialize(EMPTY_NODE);
 
     private NodeBuilder builder = root.builder();
@@ -57,8 +63,7 @@ public class LuceneIndexTest {
         builder.setProperty("foo", "bar");
         NodeState after = builder.getNodeState();
 
-        EditorDiff.process(new LuceneIndexEditor(builder), before, after);
-        NodeState indexed = builder.getNodeState();
+        NodeState indexed = HOOK.processCommit(before, after);
 
         QueryIndex queryIndex = new LuceneIndex();
         FilterImpl filter = createFilter(NT_BASE);
@@ -84,8 +89,7 @@ public class LuceneIndexTest {
 
         NodeState after = builder.getNodeState();
 
-        EditorDiff.process(new LuceneIndexEditor(builder), before, after);
-        NodeState indexed = builder.getNodeState();
+        NodeState indexed = HOOK.processCommit(before, after);
 
         QueryIndex queryIndex = new LuceneIndex();
         FilterImpl filter = createFilter(NT_BASE);
@@ -95,17 +99,18 @@ public class LuceneIndexTest {
         Cursor cursor = queryIndex.query(filter, indexed);
 
         assertTrue(cursor.hasNext());
-        assertEquals("/", cursor.next().getPath());
-        assertEquals("/a", cursor.next().getPath());
-        assertEquals("/a/b", cursor.next().getPath());
         assertEquals("/a/b/c", cursor.next().getPath());
+        assertEquals("/a/b", cursor.next().getPath());
+        assertEquals("/a", cursor.next().getPath());
+        assertEquals("/", cursor.next().getPath());
         assertFalse(cursor.hasNext());
     }
 
     @Test
     public void testLucene3() throws Exception {
         NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
-        newLuceneIndexDefinition(index, "lucene", ImmutableSet.of(Type.STRING.toString()));
+        newLuceneIndexDefinition(
+                index, "lucene", ImmutableSet.of(PropertyType.TYPENAME_STRING));
 
         NodeState before = builder.getNodeState();
         builder.setProperty("foo", "bar");
@@ -115,8 +120,7 @@ public class LuceneIndexTest {
 
         NodeState after = builder.getNodeState();
 
-        EditorDiff.process(new LuceneIndexEditor(builder), before, after);
-        NodeState indexed = builder.getNodeState();
+        NodeState indexed = HOOK.processCommit(before, after);
 
         QueryIndex queryIndex = new LuceneIndex();
         FilterImpl filter = createFilter(NT_BASE);
@@ -126,8 +130,8 @@ public class LuceneIndexTest {
         Cursor cursor = queryIndex.query(filter, indexed);
 
         assertTrue(cursor.hasNext());
-        assertEquals("/", cursor.next().getPath());
         assertEquals("/a", cursor.next().getPath());
+        assertEquals("/", cursor.next().getPath());
         assertFalse(cursor.hasNext());
     }
 

Modified: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrUtils.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrUtils.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrUtils.java Tue Jun 11 13:00:04 2013
@@ -17,10 +17,9 @@
 package org.apache.jackrabbit.oak.plugins.index.solr;
 
 import java.io.IOException;
+
 import javax.annotation.Nonnull;
 
-import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
-import org.apache.jackrabbit.oak.plugins.index.solr.index.SolrIndexHookProvider;
 import org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
 import org.apache.solr.client.solrj.SolrServer;
@@ -47,27 +46,6 @@ public class OakSolrUtils {
     }
 
     /**
-     * adapts the OSGi Solr {@link IndexEditorProvider} service
-     *
-     * @return a {@link SolrIndexHookProvider}
-     */
-    public static IndexEditorProvider adaptOsgiIndexHookProvider() {
-        IndexEditorProvider indexHookProvider = null;
-        try {
-            BundleContext ctx = BundleReference.class.cast(SolrIndexHookProvider.class
-                    .getClassLoader()).getBundle().getBundleContext();
-
-            ServiceReference serviceReference = ctx.getServiceReference(IndexEditorProvider.class.getName());
-            if (serviceReference != null) {
-                indexHookProvider = IndexEditorProvider.class.cast(ctx.getService(serviceReference));
-            }
-        } catch (Throwable e) {
-            // do nothing
-        }
-        return indexHookProvider;
-    }
-
-    /**
      * adapts the OSGi Solr {@link QueryIndexProvider} service
      *
      * @return a {@link SolrQueryIndexProvider}

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditor.java?rev=1491780&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditor.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditor.java Tue Jun 11 13:00:04 2013
@@ -0,0 +1,194 @@
+/*
+ * 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.solr.index;
+
+import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
+
+import java.io.IOException;
+
+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.plugins.index.IndexEditor;
+import org.apache.jackrabbit.oak.plugins.index.solr.OakSolrConfiguration;
+import org.apache.jackrabbit.oak.plugins.index.solr.OakSolrUtils;
+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.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.common.SolrInputDocument;
+
+/**
+ * Index editor for keeping a Solr index up to date.
+ */
+public class SolrIndexEditor implements IndexEditor {
+
+    /** Parent editor, or {@code null} if this is the root editor. */
+    private final SolrIndexEditor parent;
+
+    /** Name of this node, or {@code null} for the root node. */
+    private final String name;
+
+    /** Path of this editor, built lazily in {@link #getPath()}. */
+    private String path;
+
+    /** Index definition node builder */
+    private final NodeBuilder definition;
+
+    private final SolrServer solrServer;
+
+    private final OakSolrConfiguration configuration;
+
+    private boolean propertiesChanged = false;
+
+    SolrIndexEditor(
+            NodeBuilder definition, SolrServer solrServer,
+            OakSolrConfiguration configuration) throws CommitFailedException {
+        this.parent = null;
+        this.name = null;
+        this.path = "/";
+        this.definition = definition;
+        this.solrServer = solrServer;
+        this.configuration = configuration;
+    }
+
+    private SolrIndexEditor(SolrIndexEditor parent, String name) {
+        this.parent = parent;
+        this.name = name;
+        this.path = null;
+        this.definition = parent.definition;
+        this.solrServer = parent.solrServer;
+        this.configuration = parent.configuration;
+    }
+
+    public String getPath() {
+        if (path == null) { // => parent != null
+            path = concat(parent.getPath(), name);
+        }
+        return path;
+    }
+
+    @Override
+    public void enter(NodeState before, NodeState after) {
+    }
+
+    @Override
+    public void leave(NodeState before, NodeState after)
+            throws CommitFailedException {
+        if (propertiesChanged || !before.exists()) {
+            try {
+                solrServer.add(docFromState(after));
+            } catch (SolrServerException e) {
+                throw new CommitFailedException(
+                        "Solr", 2, "Failed to add a document to Solr", e);
+            } catch (IOException e) {
+                throw new CommitFailedException(
+                        "Solr", 6, "Failed to send data to Solr", e);
+            }
+        }
+
+        if (parent == null) {
+            try {
+                OakSolrUtils.commitByPolicy(
+                        solrServer,  configuration.getCommitPolicy());
+            } catch (SolrServerException e) {
+                throw new CommitFailedException(
+                        "Solr", 3, "Failed to commit changes to Solr", e);
+            } catch (IOException e) {
+                throw new CommitFailedException(
+                        "Solr", 6, "Failed to send data to Solr", e);
+            }
+        }
+    }
+
+    @Override
+    public void propertyAdded(PropertyState after) {
+        propertiesChanged = true;
+    }
+
+    @Override
+    public void propertyChanged(PropertyState before, PropertyState after) {
+        propertiesChanged = true;
+    }
+
+    @Override
+    public void propertyDeleted(PropertyState before) {
+        propertiesChanged = true;
+    }
+
+    @Override
+    public Editor childNodeAdded(String name, NodeState after) {
+        return new SolrIndexEditor(this, name);
+    }
+
+    @Override
+    public Editor childNodeChanged(
+            String name, NodeState before, NodeState after) {
+        return new SolrIndexEditor(this, name);
+    }
+
+    @Override
+    public Editor childNodeDeleted(String name, NodeState before)
+            throws CommitFailedException {
+        // TODO: Proper escaping
+        String path = PathUtils.concat(getPath(), name).replace("/", "\\/");
+
+        try {
+            solrServer.deleteByQuery(String.format(
+                    "%s:%s\\/*", configuration.getPathField(), path));
+        } catch (SolrServerException e) {
+            throw new CommitFailedException(
+                    "Solr", 5, "Failed to remove documents from Solr", e);
+        } catch (IOException e) {
+            throw new CommitFailedException(
+                    "Solr", 6, "Failed to send data to Solr", e);
+        }
+
+        return null; // no need to recurse down the removed subtree
+    }
+
+    private SolrInputDocument docFromState(NodeState state) {
+        SolrInputDocument inputDocument = new SolrInputDocument();
+        String path = getPath();
+        if (!path.endsWith("/")) {
+            path = path + "/";
+        }
+        inputDocument.addField(configuration.getPathField(), path);
+        for (PropertyState property : state.getProperties()) {
+            // try to get the field to use for this property from configuration
+            String fieldName = configuration.getFieldNameFor(property.getType());
+            if (fieldName != null) {
+                inputDocument.addField(
+                        fieldName, property.getValue(property.getType()));
+            } else {
+                // or fallback to adding propertyName:stringValue(s)
+                if (property.isArray()) {
+                    for (String s : property.getValue(Type.STRINGS)) {
+                        inputDocument.addField(property.getName(), s);
+                    }
+                } else {
+                    inputDocument.addField(
+                            property.getName(), property.getValue(Type.STRING));
+                }
+            }
+        }
+        return inputDocument;
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditorProvider.java (from r1491447, jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookProvider.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditorProvider.java?p2=jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditorProvider.java&p1=jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookProvider.java&r1=1491447&r2=1491780&rev=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookProvider.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditorProvider.java Tue Jun 11 13:00:04 2013
@@ -6,7 +6,7 @@
  * (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
+ *     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,
@@ -16,14 +16,13 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.solr.index;
 
-
-import javax.annotation.CheckForNull;
+import static org.apache.felix.scr.annotations.ReferencePolicy.STATIC;
+import static org.apache.felix.scr.annotations.ReferencePolicyOption.GREEDY;
 
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferencePolicy;
-import org.apache.felix.scr.annotations.ReferencePolicyOption;
 import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.plugins.index.IndexEditor;
 import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.index.solr.OakSolrConfigurationProvider;
@@ -31,47 +30,53 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex;
 import org.apache.jackrabbit.oak.spi.commit.Editor;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
- * Service that provides {@link SolrIndexHookProvider} based {@link IndexEditor}s.
- *
- * @see org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider
+ * Service that provides Lucene based {@link IndexEditor}s
+ * 
+ * @see SolrIndexEditor
+ * @see IndexEditorProvider
+ * 
  */
 @Component
 @Service(IndexEditorProvider.class)
-public class SolrIndexHookProvider implements IndexEditorProvider {
+public class SolrIndexEditorProvider implements IndexEditorProvider {
 
-    private final Logger log = LoggerFactory.getLogger(SolrIndexHookProvider.class);
-
-    @Reference(policyOption = ReferencePolicyOption.GREEDY, policy = ReferencePolicy.STATIC)
+    @Reference(policyOption = GREEDY, policy = STATIC)
     private SolrServerProvider solrServerProvider;
 
-    @Reference(policyOption = ReferencePolicyOption.GREEDY, policy = ReferencePolicy.STATIC)
+    @Reference(policyOption = GREEDY, policy = STATIC)
     private OakSolrConfigurationProvider oakSolrConfigurationProvider;
 
-    public SolrIndexHookProvider() {
-    }
-
-    public SolrIndexHookProvider(SolrServerProvider solrServerProvider, OakSolrConfigurationProvider oakSolrConfigurationProvider) {
+    public SolrIndexEditorProvider(
+            SolrServerProvider solrServerProvider,
+            OakSolrConfigurationProvider oakSolrConfigurationProvider) {
         this.solrServerProvider = solrServerProvider;
         this.oakSolrConfigurationProvider = oakSolrConfigurationProvider;
     }
 
-    @Override @CheckForNull
-    public Editor getIndexEditor(String type, NodeBuilder builder) {
-        if (SolrQueryIndex.TYPE.equals(type) && solrServerProvider != null && oakSolrConfigurationProvider != null) {
+    public SolrIndexEditorProvider() {
+    }
+
+    @Override
+    public Editor getIndexEditor(
+            String type, NodeBuilder definition, NodeState root)
+            throws CommitFailedException {
+        if (SolrQueryIndex.TYPE.equals(type)
+                && solrServerProvider != null
+                && oakSolrConfigurationProvider != null) {
             try {
-                if (log.isDebugEnabled()) {
-                    log.debug("Creating a Solr index hook");
-                }
-                return new SolrIndexDiff(builder, solrServerProvider.getSolrServer(), oakSolrConfigurationProvider.getConfiguration());
+                return new SolrIndexEditor(
+                        definition,
+                        solrServerProvider.getSolrServer(),
+                        oakSolrConfigurationProvider.getConfiguration());
             } catch (Exception e) {
-                log.error("unable to create Solr IndexHook ", e);
+                // TODO Auto-generated catch block
+                e.printStackTrace();
             }
         }
         return null;
     }
 
-}
\ No newline at end of file
+}

Propchange: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexEditorProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java Tue Jun 11 13:00:04 2013
@@ -16,11 +16,9 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.solr.query;
 
-
 import java.util.Collection;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
-import org.apache.jackrabbit.oak.plugins.index.IndexDefinition;
 import org.apache.jackrabbit.oak.plugins.index.solr.OakSolrConfiguration;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -44,19 +42,19 @@ public class SolrQueryIndex implements Q
     private static final Logger log = LoggerFactory.getLogger(SolrQueryIndex.class);
     public static final String TYPE = "solr";
 
-    private final IndexDefinition index;
+    private final String name;
     private final SolrServer solrServer;
     private final OakSolrConfiguration configuration;
 
-    public SolrQueryIndex(IndexDefinition indexDefinition, SolrServer solrServer, OakSolrConfiguration configuration) {
-        this.index = indexDefinition;
+    public SolrQueryIndex(String name, SolrServer solrServer, OakSolrConfiguration configuration) {
+        this.name = name;
         this.solrServer = solrServer;
         this.configuration = configuration;
     }
 
     @Override
     public String getIndexName() {
-        return index.getName();
+        return name;
     }
 
     @Override
@@ -94,13 +92,13 @@ public class SolrQueryIndex implements Q
             if (fieldName != null) {
                 queryBuilder.append(fieldName);
                 queryBuilder.append(':');
-                // TODO : remove this hack for all descendants of root node
-                if (path.equals("\\/") && pathRestriction.equals(Filter.PathRestriction.ALL_CHILDREN)) {
+                queryBuilder.append(path);
+                if (!path.equals("\\/")) {
+                    queryBuilder.append("\\/");
+                }
+                // TODO: Also handle other path restriction types
+                if (pathRestriction.equals(Filter.PathRestriction.ALL_CHILDREN)) {
                     queryBuilder.append("*");
-                } else {
-                    queryBuilder.append("\"");
-                    queryBuilder.append(path);
-                    queryBuilder.append("\"");
                 }
                 queryBuilder.append(" ");
             }
@@ -128,6 +126,9 @@ public class SolrQueryIndex implements Q
                     queryBuilder.append(configuration.getPathField());
                     queryBuilder.append(':');
                     queryBuilder.append(first);
+                    if (!first.equals("\\/")) {
+                        queryBuilder.append("\\/");
+                    }
                 } else {
                     queryBuilder.append(fieldName).append(':');
                     if (pr.first != null && pr.last != null && pr.first.equals(pr.last)) {
@@ -189,8 +190,7 @@ public class SolrQueryIndex implements Q
             if (c == '\\' || c == '!' || c == '(' || c == ')' ||
                     c == ':' || c == '^' || c == '[' || c == ']' || c == '/' ||
                     c == '{' || c == '}' || c == '~' || c == '*' || c == '?' ||
-                    c == '-'
-                    ) {
+                    c == '-' || c == ' ') {
                 sb.append('\\');
             }
             sb.append(c);
@@ -240,7 +240,13 @@ public class SolrQueryIndex implements Q
                 return new IndexRow() {
                     @Override
                     public String getPath() {
-                        return String.valueOf(doc.getFieldValue(configuration.getPathField()));
+                        String path = String.valueOf(doc.getFieldValue(
+                                configuration.getPathField()));
+                        if ("/".equals(path)) {
+                            return "/";
+                        } else {
+                            return path.substring(0, path.length() - 1);
+                        }
                     }
 
                     @Override

Modified: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndexProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndexProvider.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndexProvider.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndexProvider.java Tue Jun 11 13:00:04 2013
@@ -16,6 +16,9 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.solr.query;
 
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+
 import java.util.ArrayList;
 import java.util.List;
 import javax.annotation.Nonnull;
@@ -25,17 +28,17 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.ReferencePolicy;
 import org.apache.felix.scr.annotations.ReferencePolicyOption;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.jackrabbit.oak.plugins.index.IndexDefinition;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.solr.OakSolrConfigurationProvider;
 import org.apache.jackrabbit.oak.plugins.index.solr.SolrServerProvider;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
 import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.buildIndexDefinitions;
-
 /**
  * {@link QueryIndexProvider} for {@link SolrQueryIndex}
  */
@@ -63,18 +66,26 @@ public class SolrQueryIndexProvider impl
     @Override
     public List<? extends QueryIndex> getQueryIndexes(NodeState nodeState) {
         List<QueryIndex> tempIndexes = new ArrayList<QueryIndex>();
-        for (IndexDefinition child : buildIndexDefinitions(nodeState, "/",
-                SolrQueryIndex.TYPE)) {
-            if (log.isDebugEnabled()) {
-                log.debug("found a Solr index definition {}", child);
+        if (solrServerProvider == null || oakSolrConfigurationProvider == null) {
+            return tempIndexes;
+        }
+        NodeState definitions = nodeState.getChildNode(INDEX_DEFINITIONS_NAME);
+        for (ChildNodeEntry entry : definitions.getChildNodeEntries()) {
+            NodeState definition = entry.getNodeState();
+            PropertyState type = definition.getProperty(TYPE_PROPERTY_NAME);
+            if (type != null
+                    && SolrQueryIndex.TYPE.equals(type.getValue(Type.STRING))) {
+                log.debug("found a Solr index definition {}", entry.getName());
             }
             try {
-                if (solrServerProvider != null && oakSolrConfigurationProvider != null) {
-                    tempIndexes.add(new SolrQueryIndex(child, solrServerProvider.getSolrServer(), oakSolrConfigurationProvider.getConfiguration()));
-                }
+                tempIndexes.add(new SolrQueryIndex(
+                        entry.getName(),
+                        solrServerProvider.getSolrServer(),
+                        oakSolrConfigurationProvider.getConfiguration()));
             } catch (Exception e) {
-                log.error("unable to create Solr query index at {} due to {}", new Object[]{child.getPath(), e});
+                log.error("unable to create Solr query index at " + entry.getName(), e);
             }
+            
         }
         return tempIndexes;
     }

Modified: jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrBaseTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrBaseTest.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrBaseTest.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrBaseTest.java Tue Jun 11 13:00:04 2013
@@ -16,10 +16,18 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.solr;
 
+import javax.security.auth.Subject;
+
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.mk.core.MicroKernelImpl;
 import org.apache.jackrabbit.oak.core.RootImpl;
 import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
+import org.apache.jackrabbit.oak.plugins.index.solr.index.SolrIndexEditorProvider;
+import org.apache.jackrabbit.oak.spi.commit.EditorHook;
+import org.apache.jackrabbit.oak.spi.commit.PostCommitHook;
+import org.apache.jackrabbit.oak.spi.query.CompositeQueryIndexProvider;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.solr.client.solrj.SolrServer;
 import org.junit.After;
@@ -32,16 +40,21 @@ public abstract class SolrBaseTest {
 
     protected KernelNodeStore store;
     protected NodeState state;
+    protected TestUtils provider;
     protected SolrServer server;
     protected OakSolrConfiguration configuration;
+    protected EditorHook hook;
 
     @Before
     public void setUp() throws Exception {
         MicroKernel microKernel = new MicroKernelImpl();
         store = new KernelNodeStore(microKernel);
         state = createInitialState(microKernel);
-        server = TestUtils.createSolrServer();
-        configuration = TestUtils.getTestConfiguration();
+        provider = new TestUtils();
+        server = provider.getSolrServer();
+        configuration = provider.getConfiguration();
+        hook = new EditorHook(new IndexUpdateProvider(
+                new SolrIndexEditorProvider(provider, provider)));
     }
 
     @After
@@ -53,16 +66,16 @@ public abstract class SolrBaseTest {
         }
     }
 
+    protected RootImpl createRootImpl() {
+        return new RootImpl(store, hook, PostCommitHook.EMPTY, "solr-query-engine-it", new Subject(),
+                new OpenSecurityProvider(), new CompositeQueryIndexProvider());
+    }
+
     protected NodeState createInitialState(MicroKernel microKernel) {
         String jsop = "^\"a\":1 ^\"b\":2 ^\"c\":3 +\"x\":{} +\"y\":{} +\"z\":{} " +
-                "+\"solrIdx\":{\"core\":\"oak\", \"solrHome\":\"" +
-                TestUtils.SOLR_HOME_PATH + "\", \"solrConfig\":\"" +
-                TestUtils.SOLRCONFIG_PATH + "\"} ";
+                "+\"oak:index\":{\"solr\":{\"type\":\"solr\"}}";
         microKernel.commit("/", jsop, microKernel.getHeadRevision(), "test data");
         return store.getRoot();
     }
 
-    protected RootImpl createRootImpl() {
-        return new RootImpl(store);
-    }
 }

Modified: jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/TestUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/TestUtils.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/TestUtils.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/TestUtils.java Tue Jun 11 13:00:04 2013
@@ -20,73 +20,35 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
-import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.plugins.index.IndexDefinition;
-import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
-import org.apache.jackrabbit.oak.plugins.index.solr.index.SolrIndexDiff;
 import org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex;
-import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndexProvider;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
 import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.solr.client.solrj.SolrServer;
 import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
 import org.apache.solr.core.CoreContainer;
 
-import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.buildIndexDefinitions;
-
 /**
  * Utility class for tests
  */
-public class TestUtils {
+public class TestUtils
+        implements SolrServerProvider, OakSolrConfigurationProvider {
 
     static final String SOLR_HOME_PATH = "target/test-classes/solr";
     static final String SOLRCONFIG_PATH = "target/test-classes/solr/solr.xml";
 
-    public static QueryIndexProvider getTestQueryIndexProvider(final SolrServer solrServer, final OakSolrConfiguration configuration) {
-        return new QueryIndexProvider() {
-            @Nonnull
-            @Override
-            public List<? extends QueryIndex> getQueryIndexes(NodeState nodeState) {
-                List<QueryIndex> tempIndexes = new ArrayList<QueryIndex>();
-                for (IndexDefinition child : buildIndexDefinitions(nodeState, "/",
-                        SolrQueryIndex.TYPE)) {
-                    try {
-                        tempIndexes.add(new SolrQueryIndex(child, solrServer, configuration));
-                    } catch (Exception e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-                return tempIndexes;
-            }
-        };
-    }
-
-    public static IndexEditorProvider getTestIndexHookProvider(final SolrServer solrServer, final OakSolrConfiguration configuration) {
-        return new IndexEditorProvider() {
-            @Override @CheckForNull
-            public Editor getIndexEditor(String type, NodeBuilder builder) {
-                if (SolrQueryIndex.TYPE.equals(type)) {
-                    try {
-                        return new SolrIndexDiff(builder, solrServer, configuration);
-                    } catch (Exception e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-                return null;
-            }
-        };
-
-    }
-
-    public static SolrServer createSolrServer() throws Exception {
+    public static SolrServer createSolrServer() {
         CoreContainer coreContainer = new CoreContainer(SOLR_HOME_PATH);
-        coreContainer.load(SOLR_HOME_PATH, new File(SOLRCONFIG_PATH));
+        try {
+            coreContainer.load(SOLR_HOME_PATH, new File(SOLRCONFIG_PATH));
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
         return new EmbeddedSolrServer(coreContainer, "oak");
     }
 
@@ -140,4 +102,19 @@ public class TestUtils {
 
         };
     }
+
+    private final SolrServer solrServer = createSolrServer();
+
+    private final OakSolrConfiguration configuration = getTestConfiguration();
+
+    @Override
+    public SolrServer getSolrServer() {
+        return solrServer;
+    }
+
+    @Override
+    public OakSolrConfiguration getConfiguration() {
+        return configuration;
+    }
+
 }

Modified: jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHookIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHookIT.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHookIT.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHookIT.java Tue Jun 11 13:00:04 2013
@@ -36,12 +36,6 @@ import org.junit.Test;
  */
 public class SolrCommitHookIT extends SolrBaseTest {
 
-    @Override
-    protected RootImpl createRootImpl() {
-        return new RootImpl(store, new SolrCommitHook(server), PostCommitHook.EMPTY, "solr-commit-hook-it", new Subject(),
-                new OpenSecurityProvider(), new CompositeQueryIndexProvider());
-    }
-
     @Test
     public void testAddSomeNodes() throws Exception {
         Root r = createRootImpl();
@@ -63,21 +57,24 @@ public class SolrCommitHookIT extends So
 
     @Test
     public void testRemoveNode() throws Exception {
-        // pre-populate the index with a node that is already in Oak
-        SolrInputDocument doc = new SolrInputDocument();
-        doc.addField("path_exact", "z");
-        server.add(doc);
-        server.commit();
-
-        // remove the node in oak
         Root r = createRootImpl();
-        r.getTree("/").getChild("z").remove();
+
+        // Add a node
+        r.getTree("/").addChild("testRemoveNode").setProperty("foo", "bar");
         r.commit();
 
         // check the node is not in Solr anymore
         SolrQuery query = new SolrQuery();
-        query.setQuery("path_exact:z");
-        QueryResponse queryResponse = server.query(query);
-        assertTrue("item with id:z was found in the index", queryResponse.getResults().size() == 0);
+        query.setQuery("path_exact:\\/testRemoveNode\\/");
+        assertTrue("item with id:testRemoveNode was not found in the index",
+                server.query(query).getResults().size() > 0);
+
+        // remove the node in oak
+        r.getTree("/").getChild("testRemoveNode").remove();
+        r.commit();
+
+        // check the node is not in Solr anymore
+        assertTrue("item with id:testRemoveNode was found in the index",
+                server.query(query).getResults().size() == 0);
     }
 }

Modified: jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookIT.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookIT.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookIT.java Tue Jun 11 13:00:04 2013
@@ -16,15 +16,12 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.solr.index;
 
-import org.apache.jackrabbit.oak.plugins.index.IndexDefinition;
-import org.apache.jackrabbit.oak.plugins.index.IndexDefinitionImpl;
+import java.util.Set;
+
 import org.apache.jackrabbit.oak.query.ast.Operator;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.plugins.index.solr.SolrBaseTest;
 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.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.IndexRow;
@@ -32,8 +29,10 @@ import org.apache.jackrabbit.oak.spi.que
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.solr.client.solrj.SolrQuery;
 import org.junit.Test;
 
+import static com.google.common.collect.Sets.newHashSet;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
@@ -56,21 +55,11 @@ public class SolrIndexHookIT extends Sol
         builder.child("newnode").setProperty("prop", "val");
         NodeState after = builder.getNodeState();
 
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new SolrIndexHook("/", builder, server);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
         NodeState indexed = hook.processCommit(before, after);
 
-        IndexDefinition testDef = new IndexDefinitionImpl("solr",
-                "solr", "/oak:index/solr");
-        QueryIndex queryIndex = new SolrQueryIndex(testDef, server, configuration);
+        QueryIndex queryIndex = new SolrQueryIndex("solr", server, configuration);
         FilterImpl filter = new FilterImpl(null, null);
-        filter.restrictPath("newnode", Filter.PathRestriction.EXACT);
+        filter.restrictPath("/newnode", Filter.PathRestriction.EXACT);
         filter.restrictProperty("prop", Operator.EQUAL,
                 PropertyValues.newString("val"));
         Cursor cursor = queryIndex.query(filter, indexed);
@@ -78,7 +67,7 @@ public class SolrIndexHookIT extends Sol
         assertTrue("no results found", cursor.hasNext());
         IndexRow next = cursor.next();
         assertNotNull("first returned item should not be null", next);
-        assertEquals("newnode", next.getPath());
+        assertEquals("/newnode", next.getPath());
         assertFalse(cursor.hasNext());
     }
 
@@ -95,19 +84,9 @@ public class SolrIndexHookIT extends Sol
         builder.setProperty("foo", "bar");
         NodeState after = builder.getNodeState();
 
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new SolrIndexHook("/", builder, server);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
         NodeState indexed = hook.processCommit(before, after);
 
-        IndexDefinition testDef = new IndexDefinitionImpl("solr",
-                "solr", "/oak:index/solr");
-        QueryIndex queryIndex = new SolrQueryIndex(testDef, server, configuration);
+        QueryIndex queryIndex = new SolrQueryIndex("solr", server, configuration);
         FilterImpl filter = new FilterImpl(null, null);
         filter.restrictProperty("foo", Operator.EQUAL,
                 PropertyValues.newString("bar"));
@@ -139,31 +118,24 @@ public class SolrIndexHookIT extends Sol
 
         NodeState after = builder.getNodeState();
 
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new SolrIndexHook("/", builder, server);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
         NodeState indexed = hook.processCommit(before, after);
 
-        IndexDefinition testDef = new IndexDefinitionImpl("solr",
-                "solr", "/oak:index/solr");
-        QueryIndex queryIndex = new SolrQueryIndex(testDef, server, configuration);
+        QueryIndex queryIndex = new SolrQueryIndex("solr", server, configuration);
         FilterImpl filter = new FilterImpl(null, null);
         filter.restrictProperty("foo", Operator.EQUAL,
                 PropertyValues.newString("bar"));
         filter.restrictFulltextCondition("bar");
         Cursor cursor = queryIndex.query(filter, indexed);
 
-        assertTrue(cursor.hasNext());
-        assertEquals("/", cursor.next().getPath());
-        assertEquals("a", cursor.next().getPath());
-        assertEquals("a/b", cursor.next().getPath());
-        assertEquals("a/b/c", cursor.next().getPath());
-        assertFalse(cursor.hasNext());
+        Set<String> paths = newHashSet();
+        while (cursor.hasNext()) {
+            paths.add(cursor.next().getPath());
+        }
+        assertTrue(paths.remove("/"));
+        assertTrue(paths.remove("/a"));
+        assertTrue(paths.remove("/a/b"));
+        assertTrue(paths.remove("/a/b/c"));
+        assertTrue(paths.isEmpty());
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java?rev=1491780&r1=1491779&r2=1491780&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java Tue Jun 11 13:00:04 2013
@@ -27,8 +27,8 @@ import java.util.Iterator;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.api.ContentRepository;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.plugins.index.solr.OakSolrConfiguration;
 import org.apache.jackrabbit.oak.plugins.index.solr.TestUtils;
+import org.apache.jackrabbit.oak.plugins.index.solr.index.SolrIndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
 import org.apache.jackrabbit.oak.query.AbstractQueryTest;
 import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
@@ -60,13 +60,13 @@ public class SolrIndexQueryTest extends 
 
     @Override
     protected ContentRepository createRepository() {
-        OakSolrConfiguration testConfiguration = TestUtils.getTestConfiguration();
+        TestUtils provider = new TestUtils();
+        solrServer = provider.getSolrServer();
         try {
-            solrServer = TestUtils.createSolrServer();
             return new Oak().with(new InitialContent())
                     .with(new OpenSecurityProvider())
-                    .with(TestUtils.getTestQueryIndexProvider(solrServer, testConfiguration))
-                    .with(TestUtils.getTestIndexHookProvider(solrServer, testConfiguration))
+                    .with(new SolrQueryIndexProvider(provider, provider))
+                    .with(new SolrIndexEditorProvider(provider, provider))
                     .createContentRepository();
         } catch (Exception e) {
             throw new RuntimeException(e);