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 2018/09/19 06:46:43 UTC

svn commit: r1841291 [2/3] - in /jackrabbit/oak/trunk/oak-search/src: main/java/org/apache/jackrabbit/oak/plugins/index/search/ main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/ main/java/org/apache/jackrabbit/oak/plugins/index/searc...

Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexEditorContext.java Wed Sep 19 06:46:42 2018
@@ -29,9 +29,10 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.IndexingContext;
 import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
 import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
-import org.apache.jackrabbit.oak.plugins.index.search.NodeStateCloner;
 import org.apache.jackrabbit.oak.plugins.index.search.PropertyUpdateCallback;
 import org.apache.jackrabbit.oak.plugins.index.search.ReindexOperations;
+import org.apache.jackrabbit.oak.plugins.index.search.spi.binary.FulltextBinaryTextExtractor;
+import org.apache.jackrabbit.oak.plugins.index.search.util.NodeStateCloner;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -57,13 +58,13 @@ public abstract class FulltextIndexEdito
   private static final PerfLogger PERF_LOGGER =
       new PerfLogger(LoggerFactory.getLogger(FulltextIndexEditorContext.class.getName() + ".perf"));
 
-  private IndexDefinition definition;
+  protected IndexDefinition definition;
 
-  private final NodeBuilder definitionBuilder;
+  protected final NodeBuilder definitionBuilder;
 
-  private final FulltextIndexWriterFactory indexWriterFactory;
+  private final FulltextIndexWriterFactory<D> indexWriterFactory;
 
-  private FulltextIndexWriter writer = null;
+  private FulltextIndexWriter<D> writer = null;
 
   private long indexedNodes;
 
@@ -90,11 +91,11 @@ public abstract class FulltextIndexEdito
   private PropertyUpdateCallback propertyUpdateCallback;
 
   protected FulltextIndexEditorContext(NodeState root, NodeBuilder definition,
-                           @Nullable IndexDefinition indexDefinition,
-                           IndexUpdateCallback updateCallback,
-                           FulltextIndexWriterFactory indexWriterFactory,
-                           ExtractedTextCache extractedTextCache,
-                           IndexingContext indexingContext, boolean asyncIndexing) {
+                                       @Nullable IndexDefinition indexDefinition,
+                                       IndexUpdateCallback updateCallback,
+                                       FulltextIndexWriterFactory indexWriterFactory,
+                                       ExtractedTextCache extractedTextCache,
+                                       IndexingContext indexingContext, boolean asyncIndexing) {
     this.root = root;
     this.indexingContext = checkNotNull(indexingContext);
     this.definitionBuilder = definition;
@@ -113,12 +114,16 @@ public abstract class FulltextIndexEdito
     }
   }
 
+  public abstract IndexDefinition.Builder newDefinitionBuilder();
 
-  protected abstract DocumentMaker<D> newDocumentMaker(IndexDefinition.IndexingRule rule, String path);
+  public abstract DocumentMaker<D> newDocumentMaker(IndexDefinition.IndexingRule rule, String path);
 
-  protected abstract FulltextBinaryTextExtractor createBinaryTextExtractor(ExtractedTextCache extractedTextCache, IndexDefinition definition, boolean reindex);
+  protected FulltextBinaryTextExtractor createBinaryTextExtractor(ExtractedTextCache extractedTextCache,
+                                                                  IndexDefinition definition, boolean reindex) {
+    return new FulltextBinaryTextExtractor(extractedTextCache, definition, reindex);
+  }
 
-  FulltextIndexWriter getWriter() throws IOException {
+  public FulltextIndexWriter<D> getWriter() throws IOException {
     if (writer == null) {
       //Lazy initialization so as to ensure that definition is based
       //on latest NodeBuilder state specially in case of reindexing
@@ -136,14 +141,14 @@ public abstract class FulltextIndexEdito
     return propertyUpdateCallback;
   }
 
-  void setPropertyUpdateCallback(PropertyUpdateCallback propertyUpdateCallback) {
+  public void setPropertyUpdateCallback(PropertyUpdateCallback propertyUpdateCallback) {
     this.propertyUpdateCallback = propertyUpdateCallback;
   }
 
   /**
    * close writer if it's not null
    */
-  void closeWriter() throws IOException {
+  public void closeWriter() throws IOException {
     Calendar currentTime = getCalendar();
     final long start = PERF_LOGGER.start();
     boolean indexUpdated = getWriter().close(currentTime.getTimeInMillis());
@@ -175,7 +180,7 @@ public abstract class FulltextIndexEdito
   }
 
   /** Only set for testing */
-  static void setClock(Clock c) {
+  protected static void setClock(Clock c) {
     checkNotNull(c);
     clock = c;
   }
@@ -188,7 +193,8 @@ public abstract class FulltextIndexEdito
 
   public void enableReindexMode(){
     reindex = true;
-    ReindexOperations reindexOps = new ReindexOperations(root, definitionBuilder, definition.getIndexPath());
+    ReindexOperations reindexOps =
+            new ReindexOperations(root, definitionBuilder, definition.getIndexPath(), newDefinitionBuilder());
     definition = reindexOps.apply(indexDefnRewritten);
   }
 
@@ -197,7 +203,7 @@ public abstract class FulltextIndexEdito
     return indexedNodes;
   }
 
-  boolean isAsyncIndexing() {
+  public boolean isAsyncIndexing() {
     return asyncIndexing;
   }
 
@@ -205,7 +211,7 @@ public abstract class FulltextIndexEdito
     return indexedNodes;
   }
 
-  void indexUpdate() throws CommitFailedException {
+  public void indexUpdate() throws CommitFailedException {
     updateCallback.indexUpdate();
   }
 
@@ -213,7 +219,7 @@ public abstract class FulltextIndexEdito
     return definition;
   }
 
-  private FulltextBinaryTextExtractor getTextExtractor(){
+  protected FulltextBinaryTextExtractor getTextExtractor(){
     if (textExtractor == null && isAsyncIndexing()){
       //Create lazily to ensure that if its reindex case then update definition is picked
       textExtractor = createBinaryTextExtractor(extractedTextCache, definition, reindex);
@@ -240,7 +246,7 @@ public abstract class FulltextIndexEdito
     return uid;
   }
 
-  private static IndexDefinition createIndexDefinition(NodeState root, NodeBuilder definition, IndexingContext
+  private IndexDefinition createIndexDefinition(NodeState root, NodeBuilder definition, IndexingContext
       indexingContext, boolean asyncIndexing) {
     NodeState defnState = definition.getBaseState();
     if (asyncIndexing && !IndexDefinition.isDisableStoredIndexDefinition()){
@@ -258,6 +264,10 @@ public abstract class FulltextIndexEdito
             "effective post reindexing", indexingContext.getIndexPath());
       }
     }
-    return new IndexDefinition(root, defnState,indexingContext.getIndexPath());
+    return newDefinitionBuilder()
+            .root(root)
+            .defn(defnState)
+            .indexPath(indexingContext.getIndexPath())
+            .build();
   }
 }

Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexWriterFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexWriterFactory.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexWriterFactory.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/editor/FulltextIndexWriterFactory.java Wed Sep 19 06:46:42 2018
@@ -25,7 +25,7 @@ import org.apache.jackrabbit.oak.spi.sta
 /**
  * Factory class for {@link FulltextIndexWriter}s
  */
-public interface FulltextIndexWriterFactory {
+public interface FulltextIndexWriterFactory<D> {
 
     /**
      * create a new index writer instance
@@ -34,6 +34,6 @@ public interface FulltextIndexWriterFact
      * @param reindex whether or not reindex should be performed
      * @return an index writer
      */
-    FulltextIndexWriter newInstance(IndexDefinition definition, NodeBuilder definitionBuilder, boolean reindex);
+    FulltextIndexWriter<D> newInstance(IndexDefinition definition, NodeBuilder definitionBuilder, boolean reindex);
 
 }

Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndex.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndex.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndex.java Wed Sep 19 06:46:42 2018
@@ -18,10 +18,12 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.search.spi.query;
 
+import java.io.IOException;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Predicate;
 
 import javax.jcr.PropertyType;
 
@@ -42,7 +44,6 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.search.SizeEstimator;
 import org.apache.jackrabbit.oak.plugins.index.search.spi.query.FulltextIndexPlanner.PlanResult;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyValues;
-import org.apache.jackrabbit.oak.query.facet.FacetResult;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction;
@@ -53,6 +54,7 @@ import org.apache.jackrabbit.oak.spi.que
 import org.apache.jackrabbit.oak.spi.query.QueryLimits;
 import org.apache.jackrabbit.oak.spi.query.fulltext.FullTextExpression;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -67,31 +69,34 @@ import static org.apache.jackrabbit.oak.
  *
  */
 public abstract class FulltextIndex implements AdvancedQueryIndex, QueryIndex, NativeQueryIndex,
-        AdvanceFulltextQueryIndex {
+    AdvanceFulltextQueryIndex {
 
     private final Logger LOG = LoggerFactory
             .getLogger(getClass());
     private final PerfLogger PERF_LOGGER =
             new PerfLogger(LoggerFactory.getLogger(getClass() + ".perf"));
 
-    static final String ATTR_PLAN_RESULT = "oak.fulltext.planResult";
+    public static final String ATTR_PLAN_RESULT = "oak.fulltext.planResult";
 
-    protected abstract FulltextIndexTracker getIndexTracker();
+    protected abstract IndexNode acquireIndexNode(String indexPath);
 
     protected abstract String getType();
 
     protected abstract SizeEstimator getSizeEstimator(IndexPlan plan);
 
+    protected abstract Predicate<NodeState> getIndexDefinitionPredicate();
+
     protected abstract String getFulltextRequestString(IndexPlan plan, IndexNode indexNode);
 
     @Override
     public List<IndexPlan> getPlans(Filter filter, List<OrderEntry> sortOrder, NodeState rootState) {
-        Collection<String> indexPaths = new IndexLookup(rootState).collectIndexNodePaths(filter, getType());
+        Collection<String> indexPaths = new IndexLookup(rootState, getIndexDefinitionPredicate())
+                .collectIndexNodePaths(filter);
         List<IndexPlan> plans = Lists.newArrayListWithCapacity(indexPaths.size());
         for (String path : indexPaths) {
             IndexNode indexNode = null;
             try {
-                indexNode = getIndexTracker().acquireIndexNode(path, getType());
+                indexNode = acquireIndexNode(path);
 
                 if (indexNode != null) {
                     IndexPlan plan = new FulltextIndexPlanner(indexNode, path, filter, sortOrder).getPlan();
@@ -124,8 +129,8 @@ public abstract class FulltextIndex impl
     @Override
     public String getPlanDescription(IndexPlan plan, NodeState root) {
         Filter filter = plan.getFilter();
-        IndexNode index = getIndexTracker().acquireIndexNode(getPlanResult(plan).indexPath, getType());
-        checkState(index != null, "The Fulltext of type " + getType() + "  index is not available");
+        IndexNode index = acquireIndexNode(plan);
+        checkState(index != null, "The fulltext index of type " + getType() + "  index is not available");
         try {
             FullTextExpression ft = filter.getFullTextConstraint();
             StringBuilder sb = new StringBuilder(getType()).append(":");
@@ -148,7 +153,7 @@ public abstract class FulltextIndex impl
         }
     }
 
-    private static void addSyncIndexPlan(IndexPlan plan, StringBuilder sb) {
+    protected static void addSyncIndexPlan(IndexPlan plan, StringBuilder sb) {
         FulltextIndexPlanner.PlanResult pr = getPlanResult(plan);
         if (pr.hasPropertyIndexResult()) {
             FulltextIndexPlanner.PropertyIndexResult pres = pr.getPropertyIndexResult();
@@ -176,7 +181,7 @@ public abstract class FulltextIndex impl
         throw new UnsupportedOperationException("Not supported as implementing AdvancedQueryIndex");
     }
 
-    private static boolean shouldInclude(String docPath, IndexPlan plan) {
+    protected static boolean shouldInclude(String docPath, IndexPlan plan) {
         String path = getPathRestriction(plan);
 
         boolean include = true;
@@ -214,7 +219,7 @@ public abstract class FulltextIndex impl
     }
 
     protected IndexNode acquireIndexNode(IndexPlan plan) {
-        return getIndexTracker().acquireIndexNode(getPlanResult(plan).indexPath, getType());
+        return acquireIndexNode(getPlanResult(plan).indexPath);
     }
 
     protected static String getIndexName(IndexPlan plan) {
@@ -237,7 +242,7 @@ public abstract class FulltextIndex impl
         return getPropertyType(defn, pr.propertyName, typeFromRestriction);
     }
 
-    private static int getPropertyType(PropertyDefinition defn, String name, int defaultVal) {
+    protected static int getPropertyType(PropertyDefinition defn, String name, int defaultVal) {
         if (defn.isTypeDefined()) {
             return defn.getType();
         }
@@ -256,7 +261,7 @@ public abstract class FulltextIndex impl
     /**
      * Following logic is taken from org.apache.jackrabbit.core.query.lucene.JackrabbitQueryParser#parse(java.lang.String)
      */
-    static String rewriteQueryText(String textsearch) {
+    protected static String rewriteQueryText(String textsearch) {
         // replace escaped ' with just '
         StringBuilder rewritten = new StringBuilder();
         // most query parsers recognize 'AND' and 'NOT' as
@@ -301,36 +306,37 @@ public abstract class FulltextIndex impl
         return "/" + relativePath;
     }
 
-    static class FulltextResultRow {
-        final String path;
-        final double score;
-        final String suggestion;
-        final boolean isVirutal;
-        final Map<String, String> excerpts;
-        final String explanation;
-        final List<FacetResult.Facet> facets;
+    public static class FulltextResultRow {
+        public final String path;
+        public final double score;
+        public final String suggestion;
+        public final boolean isVirutal;
+        public final Map<String, String> excerpts;
+        public final String explanation;
+        private final FacetProvider facetProvider;
 
-        FulltextResultRow(String path, double score, Map<String, String> excerpts, List<FacetResult.Facet> facets, String explanation) {
+        public FulltextResultRow(String path, double score, Map<String, String> excerpts,
+                                 FacetProvider facetProvider, String explanation) {
             this.explanation = explanation;
             this.excerpts = excerpts;
-            this.facets = facets;
+            this.facetProvider = facetProvider;
             this.isVirutal = false;
             this.path = path;
             this.score = score;
             this.suggestion = null;
         }
 
-        FulltextResultRow(String suggestion, long weight) {
+        public FulltextResultRow(String suggestion, long weight) {
             this.isVirutal = true;
             this.path = "/";
             this.score = weight;
             this.suggestion = suggestion;
             this.excerpts = null;
-            this.facets = null;
+            this.facetProvider = null;
             this.explanation = null;
         }
 
-        FulltextResultRow(String suggestion) {
+        public FulltextResultRow(String suggestion) {
             this(suggestion, 1);
         }
 
@@ -338,13 +344,25 @@ public abstract class FulltextIndex impl
         public String toString() {
             return String.format("%s (%1.2f)", path, score);
         }
+
+        public List<Facet> getFacets(int numberOfFacets, String columnName) throws IOException {
+            if (facetProvider == null) {
+                return null;
+            }
+
+            return facetProvider.getFacets(numberOfFacets, columnName);
+        }
+    }
+
+    public interface FacetProvider {
+        List<Facet> getFacets(int numberOfFacets, String columnName) throws IOException;
     }
 
     /**
      * A cursor over Fulltext results. The result includes the path,
      * and the jcr:score pseudo-property as returned by Lucene.
      */
-    static class FulltextPathCursor implements Cursor {
+    protected static class FulltextPathCursor implements Cursor {
 
         private final Logger log = LoggerFactory.getLogger(getClass());
         private static final int TRAVERSING_WARNING = Integer.getInteger("oak.traversing.warning", 10000);
@@ -354,9 +372,9 @@ public abstract class FulltextIndex impl
         FulltextResultRow currentRow;
         private final SizeEstimator sizeEstimator;
         private long estimatedSize;
-        private int numberOfFacets;
+        private final int numberOfFacets;
 
-        FulltextPathCursor(final Iterator<FulltextResultRow> it, final IndexPlan plan, QueryLimits settings, SizeEstimator sizeEstimator) {
+        public FulltextPathCursor(final Iterator<FulltextResultRow> it, final IndexPlan plan, QueryLimits settings, SizeEstimator sizeEstimator) {
             pathPrefix = plan.getPathPrefix();
             this.sizeEstimator = sizeEstimator;
             Iterator<String> pathIterator = new Iterator<String>() {
@@ -445,18 +463,16 @@ public abstract class FulltextIndex impl
                         }
                     }
                     if (columnName.startsWith(QueryConstants.REP_FACET)) {
-                        List<FacetResult.Facet> facets = currentRow.facets;
                         try {
+                            List<Facet> facets = currentRow.getFacets(numberOfFacets, columnName);
                             if (facets != null) {
                                 JsopWriter writer = new JsopBuilder();
                                 writer.object();
-                                for (FacetResult.Facet f : facets) {
+                                for (Facet f : facets) {
                                     writer.key(f.getLabel()).value(f.getCount());
                                 }
                                 writer.endObject();
                                 return PropertyValues.newString(writer.toString());
-                            } else {
-                                return null;
                             }
                         } catch (Exception e) {
                             throw new RuntimeException(e);
@@ -477,7 +493,38 @@ public abstract class FulltextIndex impl
         }
     }
 
-    static String parseFacetField(String columnName) {
+    /**
+     * A query result facet, composed by its label and count.
+     */
+    public static class Facet {
+
+        private final String label;
+        private final int count;
+
+        public Facet(String label, int count) {
+            this.label = label;
+            this.count = count;
+        }
+
+        /**
+         * get the facet label
+         * @return a label
+         */
+        @NotNull
+        public String getLabel() {
+            return label;
+        }
+
+        /**
+         * get the facet count
+         * @return an integer
+         */
+        public int getCount() {
+            return count;
+        }
+    }
+
+    public static String parseFacetField(String columnName) {
         return columnName.substring(QueryConstants.REP_FACET.length() + 1, columnName.length() - 1);
     }
 }

Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNodeManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNodeManager.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNodeManager.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/IndexNodeManager.java Wed Sep 19 06:46:42 2018
@@ -25,7 +25,7 @@ import java.util.concurrent.locks.Reentr
 import org.apache.jackrabbit.oak.commons.PerfLogger;
 import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
 import org.apache.jackrabbit.oak.plugins.index.search.IndexNode;
-import org.apache.jackrabbit.oak.plugins.index.search.ReaderRefreshPolicy;
+import org.apache.jackrabbit.oak.plugins.index.search.update.ReaderRefreshPolicy;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -35,6 +35,9 @@ import static com.google.common.base.Pre
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.ASYNC_PROPERTY_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.getAsyncLaneName;
 
+/**
+ * Keeps track of the open read sessions for an index.
+ */
 public abstract class IndexNodeManager {
     /**
      * Name of the hidden node under which information about the checkpoints

Added: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/IndexUpdateListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/IndexUpdateListener.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/IndexUpdateListener.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/IndexUpdateListener.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,25 @@
+/*
+ * 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.search.update;
+
+public interface IndexUpdateListener extends ReaderRefreshPolicy {
+
+    void updated();
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/IndexUpdateListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/ReaderRefreshPolicy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/ReaderRefreshPolicy.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/ReaderRefreshPolicy.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/ReaderRefreshPolicy.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,61 @@
+/*
+ * 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.search.update;
+
+/**
+ * The refresh policy interface.
+ *
+ * A class that implements this interface decides when to refresh an index, if
+ * there was a change.
+ */
+public interface ReaderRefreshPolicy {
+
+    ReaderRefreshPolicy NEVER = new ReaderRefreshPolicy() {
+        @Override
+        public void refreshOnReadIfRequired(Runnable refreshCallback) {
+            //Never refresh
+        }
+
+        @Override
+        public void refreshOnWriteIfRequired(Runnable refreshCallback) {
+            //Never refresh
+        }
+    };
+
+    /**
+     * Invoked before any query is performed to provide a chance for IndexNode
+     * to refresh the readers
+     *
+     * The index may or may not be updated when this method is invoked.
+     *
+     * @param refreshCallback callback to refresh the readers
+     */
+    void refreshOnReadIfRequired(Runnable refreshCallback);
+
+    /**
+     * Invoked after some writes have been performed and as a final step refresh
+     * request is being made.
+     *
+     * If invoked, it can be assumed that index has been updated.
+     *
+     * @param refreshCallback callback to refresh the readers
+     */
+    void refreshOnWriteIfRequired(Runnable refreshCallback);
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/ReaderRefreshPolicy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicy.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicy.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicy.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,102 @@
+/*
+ * 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.search.update;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.jackrabbit.oak.stats.Clock;
+
+/**
+ * This policy ensures that any writes that have been done to index are made
+ * visible *before* any read is performed.
+ *
+ * Its meant as an alternative to {@link RefreshOnWritePolicy} and for "sync"
+ * indexes. For "nrt" indexes {@link TimedRefreshPolicy} should be preferred
+ *
+ * <p>
+ * The readers are not refreshed immediately upon write. Instead they would be
+ * refreshed if
+ *
+ * <ul>
+ * <li>Upon write if refreshDelta time has elapsed then readers would be
+ * refreshed</li>
+ * <li>Upon read if index is found to be updated then again readers would be
+ * refreshed</li>
+ * </ul>
+ *
+ * <p>
+ * This policy can result in some contention if index is being frequently
+ * updated and queried.
+ *
+ * *This is an experimental policy. Currently it causes high contention*
+ */
+public class RefreshOnReadPolicy implements ReaderRefreshPolicy, IndexUpdateListener {
+    private final AtomicBoolean dirty = new AtomicBoolean();
+    private final Object lock = new Object();
+    private final Clock clock;
+    private final long refreshDelta;
+    private volatile long lastRefreshTime;
+
+    public RefreshOnReadPolicy(Clock clock, TimeUnit unit, long refreshDelta) {
+        this.clock = clock;
+        this.refreshDelta = unit.toMillis(refreshDelta);
+    }
+
+    @Override
+    public void refreshOnReadIfRequired(Runnable refreshCallback) {
+        if (dirty.get()){
+            refreshWithLock(refreshCallback, false);
+        }
+    }
+
+    @Override
+    public void refreshOnWriteIfRequired(Runnable refreshCallback) {
+        long currentTime = clock.getTime();
+        if (currentTime - lastRefreshTime > refreshDelta) {
+            //Do not set dirty instead directly refresh
+            refreshWithLock(refreshCallback, true);
+        } else {
+            synchronized (lock){
+                //Needs to be done in a lock otherwise
+                //refreshWithLock would override this
+                dirty.set(true);
+            }
+        }
+    }
+
+    @Override
+    public void updated() {
+        //Detect dirty based on call from refreshOnWriteIfRequired
+        //as that would *always* be called if the index has been updated
+        //And ensures that it gets calls after all changes for that index
+        //for that transaction got committed
+    }
+
+    private void refreshWithLock(Runnable refreshCallback, boolean forceRefresh) {
+        synchronized (lock){
+            if (dirty.get() || forceRefresh) {
+                refreshCallback.run();
+                dirty.set(false);
+                lastRefreshTime = clock.getTime();
+            }
+        }
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnWritePolicy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnWritePolicy.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnWritePolicy.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnWritePolicy.java Wed Sep 19 06:46:42 2018
@@ -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.search.update;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Policy which performs immediate refresh upon completion of writes.
+ *
+ * This is the default policy for synchronous indexes.
+ */
+public class RefreshOnWritePolicy implements ReaderRefreshPolicy, IndexUpdateListener {
+    private final AtomicBoolean dirty = new AtomicBoolean();
+
+    @Override
+    public void refreshOnReadIfRequired(Runnable refreshCallback) {
+        //As writer itself refreshes the index. No refresh done
+        //on read
+    }
+
+    @Override
+    public void refreshOnWriteIfRequired(Runnable refreshCallback) {
+        //For sync indexing mode we refresh the reader immediately
+        //on the writer thread. So that any read call later sees upto date index
+        if (dirty.get()) {
+            refreshCallback.run();
+            dirty.set(false);
+        }
+    }
+
+    @Override
+    public void updated() {
+        dirty.set(true);
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnWritePolicy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/TimedRefreshPolicy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/TimedRefreshPolicy.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/TimedRefreshPolicy.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/TimedRefreshPolicy.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,69 @@
+/*
+ * 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.search.update;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.jackrabbit.oak.stats.Clock;
+
+/**
+ * This policy refreshes the index (if changed) if it wasn't refreshed for a
+ * configured time. For example once per second.
+ *
+ * It is the default policy for asynchronous indexes.
+ */
+public class TimedRefreshPolicy implements ReaderRefreshPolicy, IndexUpdateListener {
+    private final AtomicBoolean dirty = new AtomicBoolean();
+    private final Clock clock;
+    private final long refreshDelta;
+    private volatile long lastRefreshTime;
+
+    public TimedRefreshPolicy(Clock clock, TimeUnit unit, long refreshDelta) {
+        this.clock = clock;
+        this.refreshDelta = unit.toMillis(refreshDelta);
+    }
+
+    @Override
+    public void refreshOnReadIfRequired(Runnable refreshCallback) {
+        refreshIfRequired(refreshCallback);
+    }
+
+    @Override
+    public void refreshOnWriteIfRequired(Runnable refreshCallback) {
+        refreshIfRequired(refreshCallback);
+    }
+
+    @Override
+    public void updated() {
+        dirty.set(true);
+    }
+
+    private void refreshIfRequired(Runnable refreshCallback) {
+        if (dirty.get()){
+            long currentTime = clock.getTime();
+            if (currentTime - lastRefreshTime > refreshDelta
+                    && dirty.compareAndSet(true, false)){
+                lastRefreshTime = currentTime;
+                refreshCallback.run();
+            }
+        }
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/update/TimedRefreshPolicy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/ConfigUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/ConfigUtil.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/ConfigUtil.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/ConfigUtil.java Wed Sep 19 06:46:42 2018
@@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullabl
 import static com.google.common.base.Preconditions.checkArgument;
 
 /**
- * Utility class to retrieve configuration values for index definitions
+ * Utility class to retrieve configuration values for index definitions.
  */
 public class ConfigUtil {
 

Added: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/DataConversionUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/DataConversionUtil.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/DataConversionUtil.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/DataConversionUtil.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,42 @@
+/*
+ * 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.search.util;
+
+import org.apache.jackrabbit.util.ISO8601;
+
+/**
+ * Utility class to convert data from one to another format.
+ */
+public class DataConversionUtil {
+
+    /**
+     * Date values are saved with sec resolution
+     * @param date jcr data string
+     * @return date value in seconds
+     */
+    public static Long dateToLong(String date){
+        if( date == null){
+            return null;
+        }
+        //TODO OAK-2204 - Should we change the precision to lower resolution
+        return ISO8601.parse(date).getTimeInMillis();
+    }
+
+}
+

Propchange: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/DataConversionUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java Wed Sep 19 06:46:42 2018
@@ -56,7 +56,7 @@ public class FunctionIndexProcessor {
      * @return the list of properties, for example ["name"]
      */
     public static String[] getProperties(String[] functionCode) {
-        ArrayList<String> properties = new ArrayList<String>();
+        ArrayList<String> properties = new ArrayList<>();
         for(String token : functionCode) {
             if (token.startsWith("@")) {
                 String propertyName = token.substring(1);
@@ -75,7 +75,7 @@ public class FunctionIndexProcessor {
      * @return null, or the calculated value
      */
     public static PropertyState tryCalculateValue(String path, NodeState state, String[] functionCode) {
-        Deque<PropertyState> stack = new ArrayDeque<PropertyState>();
+        Deque<PropertyState> stack = new ArrayDeque<>();
         for (int i = functionCode.length - 1; i > 0; i--) {
             String token = functionCode[i];
             PropertyState ps;
@@ -108,8 +108,8 @@ public class FunctionIndexProcessor {
         return functionDescription.split("\\*");
     }
     
-    private static PropertyState calculateFunction(String functionName, 
-            Deque<PropertyState> stack) {
+    private static PropertyState calculateFunction(String functionName,
+                                                   Deque<PropertyState> stack) {
         PropertyState ps = stack.pop();
         if ("coalesce".equals(functionName)) {
             // coalesce (a, b) => (a != null ? a : b)
@@ -124,7 +124,7 @@ public class FunctionIndexProcessor {
             return ps;
         }
         Type<?> type = null;
-        ArrayList<Object> values = new ArrayList<Object>(ps.count());
+        ArrayList<Object> values = new ArrayList<>(ps.count());
         for (int i = 0; i < ps.count(); i++) {
             String s = ps.getValue(Type.STRING, i);
             Object x;
@@ -156,8 +156,8 @@ public class FunctionIndexProcessor {
         return result;
     }
     
-    private static PropertyState getProperty(String path, NodeState state, 
-            String propertyName) {
+    private static PropertyState getProperty(String path, NodeState state,
+                                             String propertyName) {
         if (PathUtils.getDepth(propertyName) != 1) {
             for(String n : PathUtils.elements(PathUtils.getParentPath(propertyName))) {
                 state = state.getChildNode(n);
@@ -169,10 +169,10 @@ public class FunctionIndexProcessor {
         }
         PropertyState ps;
         if (":localname".equals(propertyName)) {
-            ps = PropertyStates.createProperty("value", 
+            ps = PropertyStates.createProperty("value",
                     getLocalName(PathUtils.getName(path)), Type.STRING);
         } else if (":name".equals(propertyName)) {
-            ps = PropertyStates.createProperty("value", 
+            ps = PropertyStates.createProperty("value",
                     PathUtils.getName(path), Type.STRING);
         } else {
             ps = state.getProperty(propertyName);

Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilder.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionBuilder.java Wed Sep 19 06:46:42 2018
@@ -32,8 +32,8 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
 import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
 import org.apache.jackrabbit.oak.plugins.tree.factories.TreeFactory;
 import org.apache.jackrabbit.oak.spi.filter.PathFilter;
 import org.apache.jackrabbit.oak.spi.state.EqualsDiff;
@@ -47,6 +47,9 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.api.Type.STRINGS;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 
+/**
+ * A utility to build index definitions.
+ */
 public final class IndexDefinitionBuilder {
     private final NodeBuilder builder;
     private final Tree tree;
@@ -72,6 +75,7 @@ public final class IndexDefinitionBuilde
         this.builder = nodeBuilder;
         this.initial = nodeBuilder.getNodeState();
         this.tree = TreeFactory.createTree(builder);
+        tree.setProperty(FulltextIndexConstants.COMPAT_MODE, 2);
         tree.setProperty("async", "async");
         setType();
         tree.setProperty(JCR_PRIMARYTYPE, "oak:QueryIndexDefinition", NAME);

Added: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionUtils.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionUtils.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionUtils.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,130 @@
+package org.apache.jackrabbit.oak.plugins.index.search.util;
+
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.oak.api.Type.NAME;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.ASYNC_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.EXCLUDE_PROPERTY_NAMES;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.EXPERIMENTAL_STORAGE;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.INCLUDE_PROPERTY_NAMES;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.INCLUDE_PROPERTY_TYPES;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.PERSISTENCE_FILE;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.PERSISTENCE_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.PERSISTENCE_PATH;
+import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+
+/**
+ * A second utility to build index definitions.
+ */
+public class IndexDefinitionUtils {
+
+    public static NodeBuilder newFTIndexDefinition(
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes) {
+        return newFTIndexDefinition(index, name, type, propertyTypes, null, null, null);
+    }
+
+    public static NodeBuilder newFTIndexDefinition(
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes,
+        @Nullable Set<String> excludes, @Nullable String async) {
+        return newFTIndexDefinition(index, type, name, propertyTypes, excludes,
+                async, null);
+    }
+
+    public static NodeBuilder newFTIndexDefinition(
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes,
+        @Nullable Set<String> excludes, @Nullable String async,
+        @Nullable Boolean stored) {
+        if (index.hasChildNode(name)) {
+            return index.child(name);
+        }
+        index = index.child(name);
+        index.setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE, NAME)
+                .setProperty(TYPE_PROPERTY_NAME, type)
+                .setProperty(REINDEX_PROPERTY_NAME, true);
+        if (async != null) {
+            index.setProperty(ASYNC_PROPERTY_NAME, async);
+        }
+        if (propertyTypes != null && !propertyTypes.isEmpty()) {
+            index.setProperty(createProperty(INCLUDE_PROPERTY_TYPES,
+                    propertyTypes, STRINGS));
+        }
+        if (excludes != null && !excludes.isEmpty()) {
+            index.setProperty(createProperty(EXCLUDE_PROPERTY_NAMES, excludes,
+                    STRINGS));
+        }
+        if (stored != null) {
+            index.setProperty(createProperty(EXPERIMENTAL_STORAGE, stored));
+        }
+        return index;
+    }
+
+    public static NodeBuilder newFTFileIndexDefinition(
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes, @NotNull String path) {
+        return newFTFileIndexDefinition(index, type, name, propertyTypes, null,
+                path, null);
+    }
+
+    public static NodeBuilder newFTFileIndexDefinition(
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes,
+        @Nullable Set<String> excludes, @NotNull String path,
+        @Nullable String async) {
+        if (index.hasChildNode(name)) {
+            return index.child(name);
+        }
+        index = index.child(name);
+        index.setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE, NAME)
+                .setProperty(TYPE_PROPERTY_NAME, type)
+                .setProperty(PERSISTENCE_NAME, PERSISTENCE_FILE)
+                .setProperty(PERSISTENCE_PATH, path)
+                .setProperty(REINDEX_PROPERTY_NAME, true);
+        if (async != null) {
+            index.setProperty(ASYNC_PROPERTY_NAME, async);
+        }
+        if (propertyTypes != null && !propertyTypes.isEmpty()) {
+            index.setProperty(createProperty(INCLUDE_PROPERTY_TYPES,
+                    propertyTypes, STRINGS));
+        }
+        if (excludes != null && !excludes.isEmpty()) {
+            index.setProperty(createProperty(EXCLUDE_PROPERTY_NAMES, excludes,
+                    STRINGS));
+        }
+        return index;
+    }
+
+    public static NodeBuilder newFTPropertyIndexDefinition(
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @NotNull Set<String> includes,
+        @NotNull String async) {
+        checkArgument(!includes.isEmpty(), "Fulltext property index " +
+                "requires explicit list of property names to be indexed");
+
+        index = index.child(name);
+        index.setProperty(JCR_PRIMARYTYPE, INDEX_DEFINITIONS_NODE_TYPE, NAME)
+                .setProperty(TYPE_PROPERTY_NAME, type)
+                .setProperty(REINDEX_PROPERTY_NAME, true);
+        index.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+        index.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, includes, STRINGS));
+
+        if (async != null) {
+            index.setProperty(ASYNC_PROPERTY_NAME, async);
+        }
+        return index;
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexDefinitionUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexHelper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexHelper.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexHelper.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/IndexHelper.java Wed Sep 19 06:46:42 2018
@@ -48,15 +48,17 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.spi.security.user.UserConstants.GROUP_PROPERTY_NAMES;
 import static org.apache.jackrabbit.oak.spi.security.user.UserConstants.USER_PROPERTY_NAMES;
 
+/**
+ * A helper class that helps decide what to (not) index.
+ */
 public class IndexHelper {
 
     public static final Set<String> JR_PROPERTY_INCLUDES = of(TYPENAME_STRING,
             TYPENAME_BINARY);
 
     /**
-     * Nodes that represent content that shold not be tokenized (like UUIDs,
+     * Nodes that represent content that should not be tokenized (like UUIDs,
      * etc)
-     * 
      */
     private final static Set<String> NOT_TOKENIZED = newHashSet(JCR_UUID);
 
@@ -69,24 +71,24 @@ public class IndexHelper {
     }
 
     public static NodeBuilder newFTIndexDefinition(
-            @NotNull NodeBuilder index, @NotNull String name, String type,
-            @Nullable Set<String> propertyTypes) {
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes) {
         return newFTIndexDefinition(index, name, type, propertyTypes, null, null, null);
     }
 
     public static NodeBuilder newFTIndexDefinition(
-            @NotNull NodeBuilder index, @NotNull String name, String type,
-            @Nullable Set<String> propertyTypes,
-            @Nullable Set<String> excludes, @Nullable String async) {
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes,
+        @Nullable Set<String> excludes, @Nullable String async) {
         return newFTIndexDefinition(index, type, name, propertyTypes, excludes,
                 async, null);
     }
 
     public static NodeBuilder newFTIndexDefinition(
-            @NotNull NodeBuilder index, @NotNull String name, String type,
-            @Nullable Set<String> propertyTypes,
-            @Nullable Set<String> excludes, @Nullable String async,
-            @Nullable Boolean stored) {
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes,
+        @Nullable Set<String> excludes, @Nullable String async,
+        @Nullable Boolean stored) {
         if (index.hasChildNode(name)) {
             return index.child(name);
         }
@@ -112,17 +114,17 @@ public class IndexHelper {
     }
 
     public static NodeBuilder newFTFileIndexDefinition(
-            @NotNull NodeBuilder index, @NotNull String name, String type,
-            @Nullable Set<String> propertyTypes, @NotNull String path) {
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes, @NotNull String path) {
         return newFTFileIndexDefinition(index, type, name, propertyTypes, null,
                 path, null);
     }
 
     public static NodeBuilder newFTFileIndexDefinition(
-            @NotNull NodeBuilder index, @NotNull String name, String type,
-            @Nullable Set<String> propertyTypes,
-            @Nullable Set<String> excludes, @NotNull String path,
-            @Nullable String async) {
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @Nullable Set<String> propertyTypes,
+        @Nullable Set<String> excludes, @NotNull String path,
+        @Nullable String async) {
         if (index.hasChildNode(name)) {
             return index.child(name);
         }
@@ -147,9 +149,9 @@ public class IndexHelper {
     }
 
     public static NodeBuilder newFTPropertyIndexDefinition(
-            @NotNull NodeBuilder index, @NotNull String name, String type,
-            @NotNull Set<String> includes,
-            @NotNull String async) {
+        @NotNull NodeBuilder index, @NotNull String name, String type,
+        @NotNull Set<String> includes,
+        @NotNull String async) {
         checkArgument(!includes.isEmpty(), "Fulltext property index " +
                 "requires explicit list of property names to be indexed");
 
@@ -167,8 +169,7 @@ public class IndexHelper {
     }
 
     /**
-     * Nodes that represent UUIDs and shold not be tokenized
-     * 
+     * Nodes that represent UUIDs and should not be tokenized
      */
     public static boolean skipTokenization(String name) {
         return NOT_TOKENIZED.contains(name);

Added: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCloner.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCloner.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCloner.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCloner.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,58 @@
+/*
+ * 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.search.util;
+
+import org.apache.jackrabbit.oak.spi.state.ApplyDiff;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+
+/**
+ * A utility class that allows to clone a node structure, excluding hidden nodes.
+ */
+public class NodeStateCloner {
+
+    private NodeStateCloner() {
+        // a utility class
+    }
+
+    public static NodeState cloneVisibleState(NodeState state){
+        NodeBuilder builder = EMPTY_NODE.builder();
+        new ApplyVisibleDiff(builder).apply(state);
+        return builder.getNodeState();
+    }
+
+    private static class ApplyVisibleDiff extends ApplyDiff {
+        public ApplyVisibleDiff(NodeBuilder builder) {
+            super(builder);
+        }
+
+        @Override
+        public boolean childNodeAdded(String name, NodeState after) {
+            if (NodeStateUtils.isHidden(name)){
+                return true;
+            }
+            return after.compareAgainstBaseState(
+                    EMPTY_NODE, new ApplyVisibleDiff(builder.child(name)));
+        }
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCloner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCopyUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCopyUtils.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCopyUtils.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/NodeStateCopyUtils.java Wed Sep 19 06:46:42 2018
@@ -39,9 +39,17 @@ import org.apache.jackrabbit.oak.spi.sta
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
 
-final class NodeStateCopyUtils {
+/**
+ * A utility class that allows to copy a new state (including children).
+ */
+public final class NodeStateCopyUtils {
+
     private static final String OAK_CHILD_ORDER = ":childOrder";
 
+    NodeStateCopyUtils() {
+        // a utility class
+    }
+
     public static void copyToTree(NodeState state, Tree tree){
         tree.setOrderableChildren(state.hasProperty(OAK_CHILD_ORDER));
         copyProps(state, tree);

Modified: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/AggregateTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/AggregateTest.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/AggregateTest.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/AggregateTest.java Wed Sep 19 06:46:42 2018
@@ -66,7 +66,7 @@ public class AggregateTest {
     private final TestCollector col = new TestCollector();
     private final SimpleMapper mapper = new SimpleMapper();
     private final NodeState root = INITIAL_CONTENT;
-    private NodeBuilder builder = root.builder();
+    private final NodeBuilder builder = root.builder();
 
     //~---------------------------------< Node Includes >
 

Modified: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/ExtractedTextCacheTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/ExtractedTextCacheTest.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/ExtractedTextCacheTest.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/ExtractedTextCacheTest.java Wed Sep 19 06:46:42 2018
@@ -24,6 +24,7 @@ import org.apache.jackrabbit.oak.api.Blo
 import org.apache.jackrabbit.oak.plugins.index.fulltext.ExtractedText;
 import org.apache.jackrabbit.oak.plugins.index.fulltext.ExtractedText.ExtractionResult;
 import org.apache.jackrabbit.oak.plugins.index.fulltext.PreExtractedTextProvider;
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
 import org.apache.jackrabbit.oak.plugins.index.search.spi.editor.FulltextIndexEditor;
 import org.apache.jackrabbit.oak.plugins.memory.ArrayBasedBlob;
 import org.junit.Test;
@@ -122,7 +123,7 @@ public class ExtractedTextCacheTest {
 
         cache.setExtractedTextProvider(provider);
         when(provider.getText(anyString(), any(Blob.class)))
-                .thenReturn(new ExtractedText(ExtractionResult.SUCCESS, "bar"));
+            .thenReturn(new ExtractedText(ExtractionResult.SUCCESS, "bar"));
         Blob b = new IdBlob("hello", "a");
         String text = cache.get("/a", "foo", b, true);
         assertEquals("bar", text);
@@ -135,7 +136,7 @@ public class ExtractedTextCacheTest {
 
         cache.setExtractedTextProvider(provider);
         when(provider.getText(anyString(), any(Blob.class)))
-                .thenReturn(new ExtractedText(ExtractionResult.SUCCESS, "bar"));
+            .thenReturn(new ExtractedText(ExtractionResult.SUCCESS, "bar"));
         Blob b = new IdBlob("hello", "a");
         String text = cache.get("/a", "foo", b, false);
         assertEquals("bar", text);
@@ -194,7 +195,7 @@ public class ExtractedTextCacheTest {
         assertNull(cache.get("/a", "foo", b, false));
         cache.putTimeout(b, ExtractedText.ERROR);
         assertNull("Cache returned non null text for blob with null content identity",
-                cache.get("/a", "foo", b, false));
+            cache.get("/a", "foo", b, false));
     }
 
     private static class IdBlob extends ArrayBasedBlob {

Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/FieldNamesTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/FieldNamesTest.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/FieldNamesTest.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/FieldNamesTest.java Wed Sep 19 06:46:42 2018
@@ -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.search;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class FieldNamesTest {
+    @Test
+    public void checkPropertyFieldNames() {
+        assertPropertyFieldName("abc", true);
+        assertPropertyFieldName("a:b", true);
+        assertPropertyFieldName("a/b", true);
+        assertPropertyFieldName("a/b:c", true);
+        assertPropertyFieldName("a:b/c", true);
+
+        assertPropertyFieldName(FieldNames.FULLTEXT_RELATIVE_NODE + "a", false);
+        assertPropertyFieldName(FieldNames.ANALYZED_FIELD_PREFIX + "a", false);
+        assertPropertyFieldName(FieldNames.FULLTEXT, false);
+        assertPropertyFieldName(":abc", false);
+        assertPropertyFieldName("abc_facet", false);
+        assertPropertyFieldName("a:b_facet", false);
+        assertPropertyFieldName("a/b_facet", false);
+        assertPropertyFieldName("a/b:c_facet", false);
+        assertPropertyFieldName("a:b/c_facet", false);
+    }
+
+    private void assertPropertyFieldName(String name, boolean expected) {
+        Assert.assertEquals("Check for field name " + name + " doesn't meet expectation - " + expected, FieldNames.isPropertyField(name), expected);
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/FieldNamesTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinitionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinitionTest.java?rev=1841291&r1=1841290&r2=1841291&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinitionTest.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/IndexDefinitionTest.java Wed Sep 19 06:46:42 2018
@@ -69,7 +69,7 @@ public class IndexDefinitionTest {
 
     private NodeState root = INITIAL_CONTENT;
 
-    private NodeBuilder builder = root.builder();
+    private final NodeBuilder builder = root.builder();
 
     @Test
     public void defaultConfig() throws Exception{
@@ -833,7 +833,7 @@ public class IndexDefinitionTest {
     //~----------------------------------< nodetype >
 
 
-    String testNodeTypeDefn = "[oak:TestMixA]\n" +
+    final String testNodeTypeDefn = "[oak:TestMixA]\n" +
             "  mixin\n" +
             "\n" +
             "[oak:TestSuperType]\n" +

Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/FulltextBinaryTextExtractorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/FulltextBinaryTextExtractorTest.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/FulltextBinaryTextExtractorTest.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/FulltextBinaryTextExtractorTest.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,44 @@
+/*
+ * 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.search.spi.binary;
+
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.oak.InitialContentHelper.INITIAL_CONTENT;
+import static org.junit.Assert.assertTrue;
+
+public class FulltextBinaryTextExtractorTest {
+    private final NodeState root = INITIAL_CONTENT;
+
+    private final NodeBuilder builder = root.builder();
+    private final ExtractedTextCache cache = new ExtractedTextCache(1000, 10000);
+
+    @Test
+    public void tikaConfigServiceLoader() throws Exception {
+        IndexDefinition idxDefn = new IndexDefinition(root, builder.getNodeState(), "/foo");
+        FulltextBinaryTextExtractor extractor = new FulltextBinaryTextExtractor(cache, idxDefn, false);
+        assertTrue(extractor.getTikaConfig().getServiceLoader().isDynamic());
+    }
+
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/FulltextBinaryTextExtractorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/TikaParserConfigTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/TikaParserConfigTest.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/TikaParserConfigTest.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/TikaParserConfigTest.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,56 @@
+/*
+ * 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.search.spi.binary;
+
+import java.io.StringReader;
+import java.util.Set;
+
+import org.apache.commons.io.input.ReaderInputStream;
+import org.apache.tika.mime.MediaType;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class TikaParserConfigTest {
+
+    @Test
+    public void emptyParser() throws Exception{
+        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+                "<properties>\n" +
+                "  <detectors>\n" +
+                "    <detector class=\"org.apache.tika.detect.TypeDetector\"/>\n" +
+                "  </detectors>\n" +
+                "  <parsers>\n" +
+                "    <parser class=\"org.apache.tika.parser.DefaultParser\"/>\n" +
+                "    <parser class=\"org.apache.tika.parser.EmptyParser\">\n" +
+                "      <mime>application/x-archive</mime>\n" +
+                "      <mime>application/x-bzip</mime>\n" +
+                "    </parser>\n" +
+                "  </parsers>\n" +
+                "</properties>";
+
+        Set<MediaType> types = TikaParserConfig.getNonIndexedMediaTypes(
+                new ReaderInputStream(new StringReader(xml), "UTF-8"));
+        assertEquals(2, types.size());
+        assertTrue(types.contains(MediaType.parse("application/x-archive")));
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/binary/TikaParserConfigTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTest.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTest.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTest.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,42 @@
+/*
+ * 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.search.spi.query;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class FulltextIndexTest {
+
+    @Test
+    public void testParseFacetField() {
+        String field = FulltextIndex.parseFacetField("rep:facet(text)");
+        assertNotNull(field);
+        assertEquals("text", field);
+        field = FulltextIndex.parseFacetField("rep:facet(jcr:title)");
+        assertNotNull(field);
+        assertEquals("jcr:title", field);
+        field = FulltextIndex.parseFacetField("rep:facet(jcr:primaryType)");
+        assertNotNull(field);
+        assertEquals("jcr:primaryType", field);
+
+    }
+}
+

Propchange: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RecordingRunnable.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RecordingRunnable.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RecordingRunnable.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RecordingRunnable.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,45 @@
+/*
+ * 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.search.update;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+class RecordingRunnable implements Runnable {
+    private boolean invoked;
+    @Override
+    public void run() {
+        invoked = true;
+    }
+
+    public void assertInvokedAndReset(){
+        assertTrue(invoked);
+        reset();
+    }
+
+    public void assertNotInvokedAndReset(){
+        assertFalse(invoked);
+        reset();
+    }
+
+    public void reset(){
+        invoked = false;
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RecordingRunnable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicyTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicyTest.java?rev=1841291&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicyTest.java (added)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicyTest.java Wed Sep 19 06:46:42 2018
@@ -0,0 +1,83 @@
+/*
+ * 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.search.update;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.jackrabbit.oak.stats.Clock;
+import org.junit.Test;
+
+public class RefreshOnReadPolicyTest {
+    private final Clock clock = new Clock.Virtual();
+    private final RecordingRunnable refreshCallback = new RecordingRunnable();
+    private final RefreshOnReadPolicy policy = new RefreshOnReadPolicy(clock, TimeUnit.SECONDS, 1);
+    private final long refreshDelta = TimeUnit.SECONDS.toMillis(1) + 1;
+
+    @Test
+    public void noRefreshOnReadIfNotUpdated() throws Exception{
+        policy.refreshOnReadIfRequired(refreshCallback);
+        refreshCallback.assertNotInvokedAndReset();
+    }
+
+    @Test
+    public void refreshOnFirstWrite() throws Exception{
+        clock.waitUntil(System.currentTimeMillis());
+
+        policy.refreshOnWriteIfRequired(refreshCallback);
+        refreshCallback.assertInvokedAndReset();
+    }
+
+    @Test
+    public void refreshOnReadAfterWrite() throws Exception{
+        clock.waitUntil(System.currentTimeMillis());
+
+        policy.refreshOnWriteIfRequired(refreshCallback);
+        refreshCallback.reset();
+        //Call again without change in time
+        policy.refreshOnWriteIfRequired(refreshCallback);
+
+        //This time callback should not be invoked
+        refreshCallback.assertNotInvokedAndReset();
+
+        policy.refreshOnReadIfRequired(refreshCallback);
+        //On read the callback should be invoked
+        refreshCallback.assertInvokedAndReset();
+    }
+
+    @Test
+    public void refreshOnWriteWithTimeElapsed() throws Exception{
+        clock.waitUntil(System.currentTimeMillis());
+
+        policy.refreshOnWriteIfRequired(refreshCallback);
+        refreshCallback.reset();
+
+        //Call again without change in time
+        policy.refreshOnWriteIfRequired(refreshCallback);
+
+        //This time callback should not be invoked
+        refreshCallback.assertNotInvokedAndReset();
+
+        clock.waitUntil(clock.getTime() + refreshDelta);
+
+        policy.refreshOnWriteIfRequired(refreshCallback);
+        refreshCallback.assertInvokedAndReset();
+    }
+
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/update/RefreshOnReadPolicyTest.java
------------------------------------------------------------------------------
    svn:eol-style = native