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 to...@apache.org on 2013/02/21 09:51:32 UTC

svn commit: r1448550 [1/6] - in /jackrabbit/oak/trunk: ./ oak-parent/ oak-solr-core/ oak-solr-core/src/ oak-solr-core/src/main/ oak-solr-core/src/main/java/ oak-solr-core/src/main/java/org/ oak-solr-core/src/main/java/org/apache/ oak-solr-core/src/main...

Author: tommaso
Date: Thu Feb 21 08:51:30 2013
New Revision: 1448550

URL: http://svn.apache.org/r1448550
Log:
OAK-646 - oak solr index modules moved from git fork to trunk

Added:
    jackrabbit/oak/trunk/oak-solr-core/
    jackrabbit/oak/trunk/oak-solr-core/pom.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/
    jackrabbit/oak/trunk/oak-solr-core/src/main/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfiguration.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfigurationProvider.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrUtils.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrServerProvider.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/DefaultSolrHookFactory.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHook.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrHookFactory.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiff.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHook.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookProvider.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexUpdate.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrNodeStateDiff.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrObserver.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndexProvider.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/main/resources/
    jackrabbit/oak/trunk/oak-solr-core/src/test/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrBaseTest.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/TestUtils.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHookIT.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHookTest.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiffIT.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookIT.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrIndexQueryTest.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryEngineIT.java   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/currency.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/protwords.txt   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/schema.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/solrconfig.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/stopwords.txt   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/oak/conf/synonyms.txt   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/solr.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-core/src/test/resources/solr/zoo.cfg
    jackrabbit/oak/trunk/oak-solr-embedded/
    jackrabbit/oak/trunk/oak-solr-embedded/pom.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/jackrabbit/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/jackrabbit/oak/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/jackrabbit/oak/plugins/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/jackrabbit/oak/plugins/index/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/embedded/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/embedded/EmbeddedSolrConfiguration.java   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/embedded/EmbeddedSolrConfigurationProvider.java   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/embedded/EmbeddedSolrServerProvider.java   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/oak/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/oak/conf/
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/oak/conf/currency.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/oak/conf/protwords.txt   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/oak/conf/schema.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/oak/conf/solrconfig.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/oak/conf/stopwords.txt   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/oak/conf/synonyms.txt   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/solr.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-embedded/src/main/resources/solr/zoo.cfg
    jackrabbit/oak/trunk/oak-solr-embedded/src/test/
    jackrabbit/oak/trunk/oak-solr-embedded/src/test/java/
    jackrabbit/oak/trunk/oak-solr-embedded/src/test/resources/
    jackrabbit/oak/trunk/oak-solr-remote/
    jackrabbit/oak/trunk/oak-solr-remote/pom.xml   (with props)
    jackrabbit/oak/trunk/oak-solr-remote/src/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/apache/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/apache/jackrabbit/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/apache/jackrabbit/oak/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/apache/jackrabbit/oak/plugins/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/apache/jackrabbit/oak/plugins/index/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/http/
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/http/RemoteSolrConfigurationProvider.java   (with props)
    jackrabbit/oak/trunk/oak-solr-remote/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/http/RemoteSolrServerProvider.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-parent/pom.xml
    jackrabbit/oak/trunk/pom.xml

Modified: jackrabbit/oak/trunk/oak-parent/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-parent/pom.xml?rev=1448550&r1=1448549&r2=1448550&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-parent/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-parent/pom.xml Thu Feb 21 08:51:30 2013
@@ -45,6 +45,7 @@
     <mongo.port>27017</mongo.port>
     <mongo.db>MongoMKDB</mongo.db>
     <mongo.db2>MongoMKDB2</mongo.db2>
+    <solr.version>4.0.0</solr.version>
   </properties>
 
   <issueManagement>

Added: jackrabbit/oak/trunk/oak-solr-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/pom.xml?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/pom.xml (added)
+++ jackrabbit/oak/trunk/oak-solr-core/pom.xml Thu Feb 21 08:51:30 2013
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+   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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.jackrabbit</groupId>
+    <artifactId>oak-parent</artifactId>
+    <version>0.7-SNAPSHOT</version>
+    <relativePath>../oak-parent/pom.xml</relativePath>
+  </parent>
+
+  <artifactId>oak-solr-core</artifactId>
+  <name>Oak Solr core</name>
+  <description>Oak support for Apache Solr indexing and search</description>
+  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            <Export-Package>
+              org.apache.jackrabbit.oak.plugins.index.solr,
+              org.apache.solr.*
+            </Export-Package>
+            <Private-Package>
+              org.apache.jackrabbit.oak.plugins.index.solr.*
+            </Private-Package>
+            <Embed-Dependency>solr-solrj</Embed-Dependency>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-scr-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <version>2.12</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>integration-test</goal>
+              <goal>verify</goal>
+            </goals>
+            <configuration>
+              <includes>
+                <include>**/*IT.java</include>
+              </includes>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <!-- Optional OSGi dependencies, used only when running within OSGi -->
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+      <optional>true</optional>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-core</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.solr</groupId>
+      <artifactId>solr-solrj</artifactId>
+      <version>${solr.version}</version>
+    </dependency>
+
+    <!-- sorlj dependencies needed for OSGi deployments -->
+    <dependency>
+      <groupId>org.apache.zookeeper</groupId>
+      <artifactId>zookeeper</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>javax.jms</groupId>
+          <artifactId>jms</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.sun.jmx</groupId>
+          <artifactId>jmxri</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.sun.jdmk</groupId>
+          <artifactId>jmxtools</artifactId>
+        </exclusion>
+      </exclusions>
+      <version>3.3.6</version>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>jline</groupId>
+      <artifactId>jline</artifactId>
+      <version>0.9.1</version>
+      <scope>runtime</scope>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.15</version>
+      <scope>runtime</scope>
+      <optional>true</optional>
+      <exclusions>
+        <exclusion>
+          <groupId>com.sun.jdmk</groupId>
+          <artifactId>jmxtools</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>com.sun.jmx</groupId>
+          <artifactId>jmxri</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+      <version>4.1.3</version>
+      <scope>runtime</scope>
+      <optional>true</optional>
+      <exclusions>
+        <exclusion>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpmime</artifactId>
+      <version>4.1.3</version>
+      <scope>runtime</scope>
+      <optional>true</optional>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.scr.annotations</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.solr</groupId>
+      <artifactId>solr-core</artifactId>
+      <version>${solr.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.7</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-core</artifactId>
+      <version>${project.version}</version>
+      <classifier>tests</classifier>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <version>2.5</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>log4j-over-slf4j</artifactId>
+      <version>1.6.4</version>
+      <optional>true</optional>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jcl-over-slf4j</artifactId>
+      <version>1.6.4</version>
+      <optional>true</optional>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>

Propchange: jackrabbit/oak/trunk/oak-solr-core/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfiguration.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfiguration.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfiguration.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.spi.query.Filter;
+
+/**
+ * A Solr configuration holding all the possible customizable parameters that
+ * can be leveraged for an Oak search index.
+ */
+public interface OakSolrConfiguration {
+
+    /**
+     * Provide a field name to be used for indexing / searching a certain {@link Type}
+     *
+     * @param propertyType the {@link Type} to be indexed / searched
+     * @return a <code>String</code> representing the Solr field to be used for the given {@link Type}.
+     */
+    public String getFieldNameFor(Type<?> propertyType);
+
+    /**
+     * Provide the field name for indexing / searching paths
+     *
+     * @return a <code>String</code> representing the Solr field to be used for paths.
+     */
+    public String getPathField();
+
+    /**
+     * Provide a field name to search over for the given {@link Filter.PathRestriction}
+     *
+     * @param pathRestriction the {@link Filter.PathRestriction} used for filtering search results
+     * @return the field name as a <code>String</code> to be used by Solr for the given restriction
+     */
+    public String getFieldForPathRestriction(Filter.PathRestriction pathRestriction);
+
+
+    /**
+     * Provide a field name to search over for the given {@link Filter.PropertyRestriction}
+     *
+     * @param propertyRestriction the {@link Filter.PropertyRestriction} used for filtering search results
+     * @return the field name as a <code>String</code> to be used by Solr for the given restriction
+     */
+    public String getFieldForPropertyRestriction(Filter.PropertyRestriction propertyRestriction);
+
+}

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

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfigurationProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfigurationProvider.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfigurationProvider.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrConfigurationProvider.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+/**
+ * A provider for {@link OakSolrConfiguration}s
+ */
+public interface OakSolrConfigurationProvider {
+
+    /**
+     * Provides a Solr configuration for Oak
+     *
+     * @return a {@link OakSolrConfiguration}
+     */
+    public OakSolrConfiguration getConfiguration();
+}

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

Added: 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=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrUtils.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/OakSolrUtils.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import javax.annotation.Nonnull;
+
+import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.SolrServerException;
+
+/**
+ * Utilities for Oak Solr integration.
+ */
+public class OakSolrUtils {
+
+    /**
+     * Check if a given Solr instance is alive
+     *
+     * @param solrServer the {@link SolrServer} used to communicate with the Solr instance
+     * @return <code>true</code> if the given Solr instance is alive and responding
+     * @throws IOException         if any error occurs while trying to communicate with the Solr instance
+     * @throws SolrServerException
+     */
+    public static boolean checkServerAlive(@Nonnull SolrServer solrServer) throws IOException, SolrServerException {
+        return solrServer.ping().getStatus() == 0;
+    }
+}

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

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrServerProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrServerProvider.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrServerProvider.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/SolrServerProvider.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+import org.apache.solr.client.solrj.SolrServer;
+
+/**
+ * Provider of {@link SolrServer}s instances
+ */
+public interface SolrServerProvider {
+
+    /**
+     * provides an already initialized {@link SolrServer} to be used from within Oak
+     *
+     * @return a {@link SolrServer} instance
+     * @throws Exception if anything goes wrong while providing the {@link SolrServer}
+     */
+    public SolrServer getSolrServer() throws Exception;
+}

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

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/DefaultSolrHookFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/DefaultSolrHookFactory.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/DefaultSolrHookFactory.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/DefaultSolrHookFactory.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,50 @@
+/*
+ * 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 org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.plugins.index.IndexHook;
+import org.apache.jackrabbit.oak.plugins.index.solr.OakSolrConfigurationProvider;
+import org.apache.jackrabbit.oak.plugins.index.solr.SolrServerProvider;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+
+/**
+ * Default implementation of {@link SolrHookFactory}
+ */
+@Component
+@Service(value = SolrHookFactory.class)
+public class DefaultSolrHookFactory implements SolrHookFactory {
+
+    @Reference
+    private SolrServerProvider solrServerProvider;
+
+    @Reference
+    private OakSolrConfigurationProvider oakSolrConfigurationProvider;
+
+    @Override
+    public IndexHook createIndexHook(String path, NodeBuilder builder) throws Exception {
+        return new SolrIndexDiff(builder, solrServerProvider.getSolrServer(), oakSolrConfigurationProvider.getConfiguration());
+    }
+
+    @Override
+    public CommitHook createCommitHook() throws Exception {
+        return new SolrCommitHook(solrServerProvider.getSolrServer());
+    }
+}

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

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHook.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHook.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrCommitHook.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,52 @@
+/*
+ * 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 java.io.IOException;
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.solr.client.solrj.SolrServer;
+
+/**
+ * A {@link CommitHook} which sends changes to Apache Solr
+ */
+public class SolrCommitHook implements CommitHook {
+
+    private final SolrServer solrServer;
+
+    public SolrCommitHook(SolrServer solrServer) {
+        this.solrServer = solrServer;
+    }
+
+    @Nonnull
+    @Override
+    public NodeState processCommit(NodeState before, NodeState after) throws CommitFailedException {
+        try {
+            SolrNodeStateDiff diff = new SolrNodeStateDiff(solrServer);
+            after.compareAgainstBaseState(before, diff);
+            diff.postProcess(after);
+            return after;
+        } catch (IOException e) {
+            throw new CommitFailedException(
+                    "Failed to update the Solr index", e);
+        }
+    }
+
+}

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

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrHookFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrHookFactory.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrHookFactory.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrHookFactory.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,46 @@
+/*
+ * 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 org.apache.jackrabbit.oak.plugins.index.IndexHook;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+
+/**
+ * Provider interface for {@link SolrCommitHook}s and {@link SolrIndexHook}s
+ */
+public interface SolrHookFactory {
+
+    /**
+     * create a {@link SolrIndexHook} to index data on a Solr server
+     *
+     * @param path the path the created {@link SolrIndexHook} should work on
+     * @param builder the {@link NodeBuilder} to get {@link org.apache.jackrabbit.oak.spi.state.NodeState}s
+     * @return the created {@link IndexHook}
+     * @throws Exception if any failres happen during the hook creation
+     */
+    public IndexHook createIndexHook(String path, NodeBuilder builder) throws Exception;
+
+    /**
+     * create a {@link SolrCommitHook} to index data on a Solr server
+     *
+     * @return the created {@link SolrCommitHook}
+     * @throws Exception if any failres happen during the hook creation
+     */
+    public CommitHook createCommitHook() throws Exception;
+
+}

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

Added: 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=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiff.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexDiff.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,220 @@
+/*
+ * 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 java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+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.memory.MemoryNodeState;
+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.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.apache.jackrabbit.oak.spi.state.ReadOnlyBuilder;
+import org.apache.solr.client.solrj.SolrServer;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
+
+/**
+ * {@link IndexHook} implementation that is responsible for keeping the
+ * {@link org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex} up to date
+ * <p/>
+ * This handles index updates by keeping a {@link Map} of <code>String</code>
+ * and {@link SolrIndexUpdate} for each path.
+ *
+ * @see org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex
+ * @see SolrIndexHook
+ */
+public class SolrIndexDiff implements IndexHook {
+
+    private final SolrIndexDiff parent;
+
+    private final NodeBuilder node;
+
+    private final String name;
+
+    private String path;
+
+    private final Map<String, SolrIndexUpdate> updates;
+
+    private SolrServer solrServer;
+
+    private OakSolrConfiguration configuration;
+
+    private SolrIndexDiff(SolrIndexDiff parent, NodeBuilder node, SolrServer solrServer,
+                          String name, String path, Map<String, SolrIndexUpdate> updates, OakSolrConfiguration configuration) {
+        this.parent = parent;
+        this.node = node;
+        this.name = name;
+        this.path = path;
+        this.updates = updates;
+        this.solrServer = solrServer;
+        this.configuration = configuration;
+
+        // TODO : test properly on PDFs
+
+        if (node != null && node.hasChildNode("oak:index")) {
+            NodeBuilder index = node.child("oak:index");
+            for (String indexName : index.getChildNodeNames()) {
+                NodeBuilder child = index.child(indexName);
+                if (isIndexNode(child) && !this.updates.containsKey(getPath())) {
+                    this.updates.put(getPath(), new SolrIndexUpdate(
+                            getPath(), child, configuration));
+                }
+            }
+        }
+        if (node != null && name != null && !NodeStateUtils.isHidden(name)) {
+            for (SolrIndexUpdate update : updates.values()) {
+                update.insert(getPath(), node);
+            }
+        }
+    }
+
+    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);
+        } else {
+            return null;
+        }
+    }
+
+    public String getPath() {
+        if (path == null) {
+            path = concat(parent.getPath(), name);
+        }
+        return path;
+    }
+
+    private static boolean isIndexNode(NodeBuilder node) {
+        PropertyState ps = node.getProperty(JCR_PRIMARYTYPE);
+        boolean isNodeType = ps != null && !ps.isArray()
+                && ps.getValue(Type.STRING).equals("oak:queryIndexDefinition");
+        if (!isNodeType) {
+            return false;
+        }
+        PropertyState type = node.getProperty("type");
+        boolean isIndexType = type != null && !type.isArray()
+                && type.getValue(Type.STRING).equals(SolrQueryIndex.TYPE);
+        return isIndexType;
+    }
+
+    // -----------------------------------------------------< NodeStateDiff >--
+
+    @Override
+    public void propertyAdded(PropertyState after) {
+        for (SolrIndexUpdate update : updates.values()) {
+            update.insert(getPath(), node);
+        }
+    }
+
+    @Override
+    public void propertyChanged(PropertyState before, PropertyState after) {
+        for (SolrIndexUpdate update : updates.values()) {
+            update.insert(getPath(), node);
+        }
+    }
+
+    @Override
+    public void propertyDeleted(PropertyState before) {
+        for (SolrIndexUpdate update : updates.values()) {
+            update.insert(getPath(), node);
+        }
+    }
+
+    @Override
+    public void childNodeAdded(String name, NodeState after) {
+        if (NodeStateUtils.isHidden(name)) {
+            return;
+        }
+        for (SolrIndexUpdate update : updates.values()) {
+            update.insert(concat(getPath(), name), new ReadOnlyBuilder(after));
+        }
+        after.compareAgainstBaseState(MemoryNodeState.EMPTY_NODE, child(name));
+    }
+
+    @Override
+    public void childNodeChanged(String name, NodeState before, NodeState after) {
+        if (NodeStateUtils.isHidden(name)) {
+            return;
+        }
+        after.compareAgainstBaseState(before, child(name));
+    }
+
+    @Override
+    public void childNodeDeleted(String name, NodeState before) {
+        if (NodeStateUtils.isHidden(name)) {
+            return;
+        }
+        for (SolrIndexUpdate update : updates.values()) {
+            update.remove(concat(getPath(), name));
+        }
+    }
+
+    // -----------------------------------------------------< IndexHook >--
+
+    @Override
+    public void apply() throws CommitFailedException {
+        for (SolrIndexUpdate update : updates.values()) {
+            update.apply(solrServer);
+        }
+    }
+
+    @Override
+    public void reindex(NodeBuilder state) throws CommitFailedException {
+        boolean reindex = false;
+        for (SolrIndexUpdate update : updates.values()) {
+            if (update.getAndResetReindexFlag()) {
+                reindex = true;
+            }
+        }
+        if (reindex) {
+            state.getNodeState().compareAgainstBaseState(
+                    MemoryNodeState.EMPTY_NODE,
+                    new SolrIndexDiff(null, state, solrServer, null, "/", updates, configuration));
+        }
+    }
+
+    @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();
+        }
+        updates.clear();
+    }
+
+}

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

Added: 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=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHook.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHook.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,253 @@
+/*
+ * 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 java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import javax.annotation.Nonnull;
+
+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.spi.state.ChildNodeEntry;
+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 org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.common.SolrInputDocument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link IndexHook} implementation that is responsible for keeping the
+ * {@link org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex} up to date
+ * <p/>
+ * This handles the status of the index update inside a flat list of {@link SolrInputDocument}s
+ * for additions and a {@link StringBuilder} of ids for deletions of documents.
+ * <p/>
+ * Note also that at the moment this is not configurable but assumes Solr has been
+ * configured ot have some specific fields and analyzers..
+ *
+ * @see org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex
+ * @see SolrIndexDiff
+ */
+public class SolrIndexHook implements IndexHook {
+
+    private static final Logger log = LoggerFactory.getLogger(SolrNodeStateDiff.class);
+
+    private final Collection<SolrInputDocument> solrInputDocuments;
+
+    private final StringBuilder deleteByIdQueryBuilder;
+    private final String path;
+    private final String uniqueKey;
+
+    private IOException exception;
+    private final SolrServer solrServer;
+    private final NodeBuilder nodebuilder;
+
+    public SolrIndexHook(String path, NodeBuilder nodeBuilder, SolrServer solrServer) {
+        this.nodebuilder = nodeBuilder;
+        this.path = path;
+        this.solrServer = solrServer;
+        this.uniqueKey = "path_exact";
+        this.solrInputDocuments = new LinkedList<SolrInputDocument>();
+        this.deleteByIdQueryBuilder = initializeDeleteQueryBuilder();
+    }
+
+
+    private Collection<SolrInputDocument> docsFromState(String path, @Nonnull NodeState state) {
+        List<SolrInputDocument> solrInputDocuments = new LinkedList<SolrInputDocument>();
+        SolrInputDocument inputDocument = docFromState(path, state);
+        solrInputDocuments.add(inputDocument);
+        for (ChildNodeEntry childNodeEntry : state.getChildNodeEntries()) {
+            solrInputDocuments.addAll(docsFromState(new StringBuilder(path).append('/').
+                    append(childNodeEntry.getName()).toString(), childNodeEntry.getNodeState()));
+        }
+
+        return solrInputDocuments;
+    }
+
+    private SolrInputDocument docFromState(String path, NodeState state) {
+        SolrInputDocument inputDocument = new SolrInputDocument();
+        // TODO : make id field configurable
+        inputDocument.addField(uniqueKey, path);
+        for (PropertyState propertyState : state.getProperties()) {
+            // TODO : enable selecting field from property type
+            if (propertyState.isArray()) {
+                for (String s : propertyState.getValue(Type.STRINGS)) {
+                    inputDocument.addField(propertyState.getName(), s);
+                }
+            } else {
+                inputDocument.addField(propertyState.getName(), propertyState.getValue(Type.STRING));
+            }
+        }
+        return inputDocument;
+    }
+
+    @Override
+    public void propertyAdded(PropertyState after) {
+        solrInputDocuments.add(docFromState(getPath(), nodebuilder.getNodeState()));
+    }
+
+    @Override
+    public void propertyChanged(PropertyState before, PropertyState after) {
+        solrInputDocuments.add(docFromState(getPath(), nodebuilder.getNodeState()));
+    }
+
+    @Override
+    public void propertyDeleted(PropertyState before) {
+        solrInputDocuments.add(docFromState(getPath(), nodebuilder.getNodeState()));
+    }
+
+    @Override
+    public void childNodeAdded(String name, NodeState after) {
+        if (NodeStateUtils.isHidden(name)) {
+            return;
+        }
+        if (exception == null) {
+            try {
+                addSubtree(name, after);
+            } catch (IOException e) {
+                exception = e;
+            }
+        }
+    }
+
+    private void addSubtree(String name, NodeState nodeState) throws IOException {
+        solrInputDocuments.addAll(docsFromState(name, nodeState));
+    }
+
+    @Override
+    public void 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);
+            }
+
+        }
+    }
+
+    @Override
+    public void childNodeDeleted(String name, NodeState before) {
+        if (NodeStateUtils.isHidden(name)) {
+            return;
+        }
+        if (exception == null) {
+            try {
+                deleteSubtree(name, before);
+            } catch (IOException e) {
+                exception = e;
+            }
+        }
+    }
+
+    private void deleteSubtree(String name, NodeState before) throws IOException {
+        // TODO : handle cases where default operator is AND
+        for (SolrInputDocument doc : docsFromState(name, before)) {
+            deleteByIdQueryBuilder.append(doc.getFieldValue(uniqueKey)).append(" ");
+        }
+    }
+
+    private StringBuilder initializeDeleteQueryBuilder() {
+        return new StringBuilder(uniqueKey).append(":(");
+    }
+
+    @Override
+    public void apply() throws CommitFailedException {
+        try {
+            if (exception != null) {
+                throw exception;
+            }
+            boolean somethingToSend = false;
+            try {
+                // handle adds
+                if (solrInputDocuments.size() > 0) {
+                    solrServer.add(solrInputDocuments);
+                    somethingToSend = true;
+                }
+                // handle deletions
+                if (deleteByIdQueryBuilder.length() > 12) {
+                    solrServer.deleteByQuery(deleteByIdQueryBuilder.append(")").toString());
+                    if (!somethingToSend) {
+                        somethingToSend = true;
+                    }
+                }
+
+            } catch (SolrServerException e) {
+                throw new IOException(e);
+            }
+
+            if (somethingToSend) {
+                solrServer.commit(false, false, true); // default to softCommit
+            }
+
+            if (log.isDebugEnabled()) {
+                log.debug(new StringBuilder("added ").append(solrInputDocuments.size()).append(" documents").toString());
+            }
+
+        } catch (Exception e) {
+            try {
+                if (solrServer != null) {
+                    solrServer.rollback();
+                }
+            } catch (Exception e1) {
+                log.warn("An error occurred while rollback-ing too {}", e);
+            }
+            throw new CommitFailedException(e);
+        }
+    }
+
+    @Override
+    public void reindex(NodeBuilder state) throws CommitFailedException {
+        try {
+            close();
+            deleteByIdQueryBuilder.append(getPath()).append("*");
+            solrInputDocuments.addAll(docsFromState(getPath(), state.getNodeState()));
+            apply();
+        } catch (IOException e) {
+            throw new CommitFailedException(e);
+        }
+
+    }
+
+    @Override
+    public void close() throws IOException {
+        solrInputDocuments.clear();
+        deleteByIdQueryBuilder.delete(4, deleteByIdQueryBuilder.length());
+    }
+
+    @Override
+    public IndexHook child(String name) {
+        return new SolrIndexHook(name, nodebuilder, solrServer);
+    }
+
+    @Override
+    public String getPath() {
+        return path;
+    }
+}

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

Added: 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/SolrIndexHookProvider.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookProvider.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexHookProvider.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,65 @@
+/*
+ * 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 java.util.List;
+import javax.annotation.Nonnull;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.plugins.index.IndexHook;
+import org.apache.jackrabbit.oak.plugins.index.IndexHookProvider;
+import org.apache.jackrabbit.oak.plugins.index.solr.query.SolrQueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Service that provides {@link SolrIndexHookProvider} based {@link IndexHook}s.
+ *
+ * @see org.apache.jackrabbit.oak.plugins.index.IndexHookProvider
+ */
+@Component
+@Service(IndexHookProvider.class)
+public class SolrIndexHookProvider implements IndexHookProvider {
+
+    @Reference
+    private SolrHookFactory hookFactory;
+
+    private final Logger log = LoggerFactory.getLogger(SolrIndexHookProvider.class);
+
+    @Override
+    @Nonnull
+    public List<? extends IndexHook> getIndexHooks(String type, NodeBuilder builder) {
+        if (SolrQueryIndex.TYPE.equals(type)) {
+            if (log.isInfoEnabled()) {
+                log.info("Creating a Solr index hook");
+            }
+            try {
+                IndexHook indexHook = hookFactory.createIndexHook("/", builder);
+                return ImmutableList.of(indexHook);
+            } catch (Exception e) {
+                log.error("unable to create Solr IndexHook ", e);
+            }
+        }
+        return ImmutableList.of();
+    }
+
+}
\ No newline at end of file

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

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexUpdate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexUpdate.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexUpdate.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrIndexUpdate.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,177 @@
+/*
+ * 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 java.io.Closeable;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import javax.annotation.Nonnull;
+
+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.solr.OakSolrConfiguration;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+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;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * A Solr index update
+ */
+public class SolrIndexUpdate implements Closeable {
+
+    private final String path;
+
+    private final NodeBuilder index;
+    private OakSolrConfiguration configuration;
+
+    private final Map<String, NodeState> insert = new TreeMap<String, NodeState>();
+
+    private final Set<String> remove = new TreeSet<String>();
+
+    public SolrIndexUpdate(String path, NodeBuilder index, OakSolrConfiguration configuration) {
+        this.path = path;
+        this.index = index;
+        this.configuration = configuration;
+    }
+
+    public void insert(String path, NodeBuilder value) {
+        Preconditions.checkArgument(path.startsWith(this.path));
+        if (!insert.containsKey(path)) {
+            String key = path.substring(this.path.length());
+            if ("".equals(key)) {
+                key = "/";
+            }
+            if (value != null) {
+                insert.put(key, value.getNodeState());
+            }
+        }
+    }
+
+    public void remove(String path) {
+        Preconditions.checkArgument(path.startsWith(this.path));
+        remove.add(path.substring(this.path.length()));
+    }
+
+    boolean getAndResetReindexFlag() {
+        boolean reindex = index.getProperty("reindex") != null
+                && index.getProperty("reindex").getValue(
+                Type.BOOLEAN);
+        index.setProperty("reindex", false);
+        return reindex;
+    }
+
+    public void apply(SolrServer solrServer) throws CommitFailedException {
+        if (remove.isEmpty() && insert.isEmpty()) {
+            return;
+        }
+        try {
+            for (String p : remove) {
+                deleteSubtreeWriter(solrServer, p);
+            }
+            for (String p : insert.keySet()) {
+                NodeState ns = insert.get(p);
+                addSubtreeWriter(solrServer, p, ns);
+            }
+            solrServer.commit(false, false, true);
+        } catch (IOException e) {
+            throw new CommitFailedException(
+                    "Failed to update the full text search index", e);
+        } catch (SolrServerException e) {
+            throw new CommitFailedException(
+                    "Failed to update the full text search index", e);
+        } finally {
+            remove.clear();
+            insert.clear();
+        }
+    }
+
+    private Collection<SolrInputDocument> docsFromState(String path, @Nonnull NodeState state) {
+        List<SolrInputDocument> solrInputDocuments = new LinkedList<SolrInputDocument>();
+        SolrInputDocument inputDocument = docFromState(path, state);
+        solrInputDocuments.add(inputDocument);
+        for (ChildNodeEntry childNodeEntry : state.getChildNodeEntries()) {
+            solrInputDocuments.addAll(docsFromState(new StringBuilder(path).append('/').
+                    append(childNodeEntry.getName()).toString(), childNodeEntry.getNodeState()));
+        }
+
+        return solrInputDocuments;
+    }
+
+    private SolrInputDocument docFromState(String path, NodeState state) {
+        SolrInputDocument inputDocument = new SolrInputDocument();
+        inputDocument.addField(configuration.getPathField(), path);
+        for (PropertyState propertyState : state.getProperties()) {
+            // try to get the field to use for this property from configuration
+            String fieldName = configuration.getFieldNameFor(propertyState.getType());
+            if (fieldName != null) {
+                inputDocument.addField(fieldName, propertyState.getValue(propertyState.getType()));
+            } else {
+                // or fallback to adding propertyName:stringValue(s)
+                if (propertyState.isArray()) {
+                    for (String s : propertyState.getValue(Type.STRINGS)) {
+                        inputDocument.addField(propertyState.getName(), s);
+                    }
+                } else {
+                    inputDocument.addField(propertyState.getName(), propertyState.getValue(Type.STRING));
+                }
+            }
+        }
+        return inputDocument;
+    }
+
+    private void deleteSubtreeWriter(SolrServer solrServer, String path)
+            throws IOException, SolrServerException {
+        // TODO verify the removal of the entire sub-hierarchy
+        if (!path.startsWith("/")) {
+            path = "/" + path;
+        }
+        solrServer.deleteByQuery(new StringBuilder(configuration.getPathField())
+                .append(':').append(path).append("*").toString());
+    }
+
+    private void addSubtreeWriter(SolrServer solrServer, String path,
+                                  NodeState state) throws IOException, SolrServerException {
+        if (!path.startsWith("/")) {
+            path = "/" + path;
+        }
+        solrServer.add(docFromState(path, state));
+    }
+
+    @Override
+    public void close() throws IOException {
+        remove.clear();
+        insert.clear();
+    }
+
+    @Override
+    public String toString() {
+        return "SolrIndexUpdate [path=" + path + ", insert=" + insert
+                + ", remove=" + remove + "]";
+    }
+}

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

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrNodeStateDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrNodeStateDiff.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrNodeStateDiff.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrNodeStateDiff.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,193 @@
+/*
+ * 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 java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import javax.annotation.Nonnull;
+
+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.state.ChildNodeEntry;
+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.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.common.SolrInputDocument;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Solr based {@link IndexHook}
+ */
+class SolrNodeStateDiff implements NodeStateDiff {
+
+    private static final Logger log = LoggerFactory.getLogger(SolrNodeStateDiff.class);
+
+    private final Collection<SolrInputDocument> solrInputDocuments;
+
+    private final StringBuilder deleteByIdQueryBuilder;
+
+    private final SolrServer solrServer;
+
+    private IOException exception;
+
+    public SolrNodeStateDiff(SolrServer solrServer) {
+        this.solrServer = solrServer;
+        solrInputDocuments = new LinkedList<SolrInputDocument>();
+        deleteByIdQueryBuilder = initializeDeleteQueryBuilder();
+    }
+
+    public void postProcess(NodeState state) throws IOException {
+        if (exception != null) {
+            throw exception;
+        }
+        try {
+            // handle adds
+            if (solrInputDocuments.size() > 0) {
+                solrServer.add(solrInputDocuments);
+            }
+            // handle deletions
+            if (deleteByIdQueryBuilder.length() > 12) {
+                solrServer.deleteByQuery(deleteByIdQueryBuilder.append(")").toString());
+            }
+
+            // default to softCommit
+            solrServer.commit(false, false, true);
+
+            if (log.isDebugEnabled()) {
+                log.debug(new StringBuilder("added ").append(solrInputDocuments.size()).append(" documents").toString());
+            }
+
+            // free structures
+            solrInputDocuments.clear();
+            deleteByIdQueryBuilder.delete(4, deleteByIdQueryBuilder.length());
+        } catch (SolrServerException e) {
+            try {
+                if (solrServer != null) {
+                    solrServer.rollback();
+                }
+            } catch (SolrServerException e1) {
+                // do nothing
+            }
+            throw new IOException(e);
+        }
+    }
+
+    private Collection<SolrInputDocument> docsFromState(String path, @Nonnull NodeState state) {
+        List<SolrInputDocument> solrInputDocuments = new LinkedList<SolrInputDocument>();
+        SolrInputDocument inputDocument = new SolrInputDocument();
+        // TODO : make id field configurable
+        inputDocument.addField("path_exact", path);
+        for (PropertyState propertyState : state.getProperties()) {
+            // TODO : enable selecting field from property type
+            if (propertyState.isArray()) {
+                for (String s : propertyState.getValue(Type.STRINGS)) {
+                    inputDocument.addField(propertyState.getName(), s);
+                }
+            } else {
+                inputDocument.addField(propertyState.getName(), propertyState.getValue(Type.STRING));
+            }
+        }
+        solrInputDocuments.add(inputDocument);
+        for (ChildNodeEntry childNodeEntry : state.getChildNodeEntries()) {
+            solrInputDocuments.addAll(docsFromState(new StringBuilder(path).append('/').
+                    append(childNodeEntry.getName()).toString(), childNodeEntry.getNodeState()));
+        }
+
+        return solrInputDocuments;
+    }
+
+    @Override
+    public void propertyAdded(PropertyState after) {
+        // TODO implement this
+    }
+
+    @Override
+    public void propertyChanged(PropertyState before, PropertyState after) {
+        // TODO implement this
+    }
+
+    @Override
+    public void propertyDeleted(PropertyState before) {
+        // TODO implement this
+    }
+
+    @Override
+    public void childNodeAdded(String name, NodeState after) {
+        if (NodeStateUtils.isHidden(name)) {
+            return;
+        }
+        if (exception == null) {
+            try {
+                addSubtree(name, after);
+            } catch (IOException e) {
+                exception = e;
+            }
+        }
+    }
+
+    private void addSubtree(String name, NodeState after) throws IOException {
+        solrInputDocuments.addAll(docsFromState(name, after));
+    }
+
+    @Override
+    public void childNodeChanged(String name, NodeState before, NodeState after) {
+        if (NodeStateUtils.isHidden(name)) {
+            return;
+        }
+        if (exception == null) {
+            try {
+                SolrNodeStateDiff diff = new SolrNodeStateDiff(solrServer);
+                after.compareAgainstBaseState(before, diff);
+                diff.postProcess(after);
+            } catch (IOException e) {
+                exception = e;
+            }
+        }
+    }
+
+    @Override
+    public void childNodeDeleted(String name, NodeState before) {
+        if (NodeStateUtils.isHidden(name)) {
+            return;
+        }
+        if (exception == null) {
+            try {
+                deleteSubtree(name, before);
+            } catch (IOException e) {
+                exception = e;
+            }
+        }
+    }
+
+    private void deleteSubtree(String name, NodeState before) throws IOException {
+        // TODO : handle cases where default operator is AND
+        for (SolrInputDocument doc : docsFromState(name, before)) {
+            deleteByIdQueryBuilder.append(doc.getFieldValue("path_exact")).append(" ");
+        }
+    }
+
+    private StringBuilder initializeDeleteQueryBuilder() {
+        return new StringBuilder("path_exact:(");
+    }
+
+}

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

Added: jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrObserver.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrObserver.java?rev=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrObserver.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/index/SolrObserver.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.solr.index;
+
+import java.io.IOException;
+
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.solr.client.solrj.SolrServer;
+
+/**
+ * a Solr based {@link Observer}
+ */
+public class SolrObserver implements Observer {
+
+    private final SolrServer solrServer;
+
+    public SolrObserver(SolrServer solrServer) {
+        this.solrServer = solrServer;
+    }
+
+    @Override
+    public void contentChanged(NodeState before, NodeState after) {
+        SolrNodeStateDiff diff = new SolrNodeStateDiff(solrServer);
+        after.compareAgainstBaseState(before, diff);
+        try {
+            diff.postProcess(after);
+        } catch (IOException e) {
+            // do nothing
+        }
+    }
+
+}

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

Added: 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=1448550&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java (added)
+++ jackrabbit/oak/trunk/oak-solr-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/solr/query/SolrQueryIndex.java Thu Feb 21 08:51:30 2013
@@ -0,0 +1,250 @@
+/*
+ * 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.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;
+import org.apache.jackrabbit.oak.spi.query.IndexRow;
+import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Solr based {@link QueryIndex}
+ */
+public class SolrQueryIndex implements QueryIndex {
+
+    private static final Logger log = LoggerFactory.getLogger(SolrQueryIndex.class);
+    public static final String TYPE = "solr";
+
+    private final IndexDefinition index;
+    private final SolrServer solrServer;
+    private final OakSolrConfiguration configuration;
+
+    public SolrQueryIndex(IndexDefinition indexDefinition, SolrServer solrServer, OakSolrConfiguration configuration) {
+        this.index = indexDefinition;
+        this.solrServer = solrServer;
+        this.configuration = configuration;
+    }
+
+    @Override
+    public String getIndexName() {
+        return index.getName();
+    }
+
+    @Override
+    public double getCost(Filter filter, NodeState root) {
+        // TODO : estimate no of returned values and 0 is not good for no restrictions
+        return (filter.getPropertyRestrictions() != null ? filter.getPropertyRestrictions().size() * 0.1 : 0)
+                + (filter.getFulltextConditions() != null ? filter.getFulltextConditions().size() * 0.01 : 0)
+                + (filter.getPathRestriction() != null ? 0.2 : 0);
+    }
+
+    @Override
+    public String getPlan(Filter filter, NodeState nodeState) {
+        return getQuery(filter).toString();
+    }
+
+    private SolrQuery getQuery(Filter filter) {
+
+        SolrQuery solrQuery = new SolrQuery();
+        solrQuery.setParam("q.op", "AND");
+        solrQuery.setParam("df", "catch_all");
+        // TODO : can we handle this better?
+        solrQuery.setParam("rows", String.valueOf(Integer.MAX_VALUE));
+
+        StringBuilder queryBuilder = new StringBuilder();
+
+        // TODO : handle node type restriction
+
+        Filter.PathRestriction pathRestriction = filter.getPathRestriction();
+        if (pathRestriction != null) {
+            String path = purgePath(filter);
+            String fieldName = configuration.getFieldForPathRestriction(pathRestriction);
+            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("*");
+                } else {
+//                    queryBuilder.append("\"");
+                    queryBuilder.append(path);
+//                    queryBuilder.append("\"");
+                }
+                queryBuilder.append(" ");
+            }
+        }
+        Collection<Filter.PropertyRestriction> propertyRestrictions = filter.getPropertyRestrictions();
+        if (propertyRestrictions != null && !propertyRestrictions.isEmpty()) {
+            for (Filter.PropertyRestriction pr : propertyRestrictions) {
+
+                String first = null;
+                if (pr.first != null) {
+                    first = partialEscape(String.valueOf(pr.first.getValue(pr.first.getType()))).toString();
+                }
+                String last = null;
+                if (pr.last != null) {
+                    last = partialEscape(String.valueOf(pr.last.getValue(pr.last.getType()))).toString();
+                }
+
+                String prField = configuration.getFieldForPropertyRestriction(pr);
+                CharSequence fieldName = partialEscape(prField != null ?
+                        prField : pr.propertyName);
+                if ("jcr\\:path".equals(fieldName.toString())) {
+                    queryBuilder.append(configuration.getPathField());
+                    queryBuilder.append(':');
+                    queryBuilder.append(first);
+                } else {
+                    queryBuilder.append(fieldName).append(':');
+                    if (pr.first != null && pr.last != null && pr.first.equals(pr.last)) {
+                        queryBuilder.append(first);
+                    } else if (pr.first == null && pr.last == null) {
+                        queryBuilder.append('*');
+                    } else if ((pr.first != null && pr.last == null) || (pr.last != null && pr.first == null) || (!pr.first.equals(pr.last))) {
+                        // TODO : need to check if this works for all field types (most likely not!)
+                        queryBuilder.append(createRangeQuery(first, last, pr.firstIncluding, pr.lastIncluding));
+                    } else if (pr.isLike) {
+                        // TODO : the current parameter substitution is not expected to work well
+                        queryBuilder.append(partialEscape(String.valueOf(pr.first.getValue(pr.first.getType())).replace('%', '*').replace('_', '?')));
+                    } else {
+                        throw new RuntimeException("[unexpected!] not handled case");
+                    }
+                }
+                queryBuilder.append(" ");
+            }
+        }
+
+        Collection<String> fulltextConditions = filter.getFulltextConditions();
+        for (String fulltextCondition : fulltextConditions) {
+            queryBuilder.append(fulltextCondition).append(" ");
+        }
+
+        String escapedQuery = queryBuilder.toString();
+        solrQuery.setQuery(escapedQuery);
+
+        if (log.isInfoEnabled()) {
+            log.info(new StringBuilder("JCR query: \n" + filter.getQueryStatement() + " \nhas been converted to Solr query: \n").
+                    append(solrQuery.toString()).toString());
+        }
+
+        return solrQuery;
+    }
+
+    private String createRangeQuery(String first, String last, boolean firstIncluding, boolean lastIncluding) {
+        // TODO : handle inclusion / exclusion of bounds
+        StringBuilder rangeQueryBuilder = new StringBuilder("[");
+        rangeQueryBuilder.append(first != null ? first : "*");
+        rangeQueryBuilder.append(" TO ");
+        rangeQueryBuilder.append(last != null ? last : "*");
+        rangeQueryBuilder.append("]");
+        return rangeQueryBuilder.toString();
+    }
+
+    private String purgePath(Filter filter) {
+        return partialEscape(filter.getPath()).toString();
+    }
+
+
+    // partially borrowed from SolrPluginUtils#partialEscape
+    private CharSequence partialEscape(CharSequence s) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '\\' || c == '!' || c == '(' || c == ')' ||
+                    c == ':' || c == '^' || c == '[' || c == ']' || c == '/' ||
+                    c == '{' || c == '}' || c == '~' || c == '*' || c == '?' ||
+                    c == '-'
+                    ) {
+                sb.append('\\');
+            }
+            sb.append(c);
+        }
+        return sb;
+    }
+
+    @Override
+    public Cursor query(Filter filter, NodeState root) {
+        Cursor cursor;
+        try {
+            SolrQuery query = getQuery(filter);
+            QueryResponse queryResponse = solrServer.query(query);
+            cursor = new SolrCursor(queryResponse);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return cursor;
+    }
+
+
+    private class SolrCursor implements Cursor {
+
+        private final SolrDocumentList results;
+
+        private int i;
+
+        public SolrCursor(QueryResponse queryResponse) {
+            this.results = queryResponse.getResults();
+            i = 0;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return results != null && i < results.size();
+        }
+
+        @Override
+        public void remove() {
+            results.remove(i);
+        }
+
+        public IndexRow next() {
+            if (i < results.size()) {
+                final SolrDocument doc = results.get(i);
+                i++;
+                return new IndexRow() {
+                    @Override
+                    public String getPath() {
+                        return String.valueOf(doc.getFieldValue(configuration.getPathField()));
+                    }
+
+                    @Override
+                    public PropertyValue getValue(String columnName) {
+                        String s = doc.getFieldValue(columnName).toString();
+                        return PropertyValues.newString(s);
+                    }
+
+                };
+            } else {
+                return null;
+            }
+        }
+    }
+}

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