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

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

Author: jukka
Date: Tue Apr 23 17:06:54 2013
New Revision: 1471042

URL: http://svn.apache.org/r1471042
Log:
OAK-325: QueryEngine can't handle node type hierarchies

Add full type information to SelectorImpl and index definitions and leverage it throughout the query engine

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexLookup.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyNodeState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Filter.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeState.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java
    jackrabbit/oak/trunk/oak-jcr/pom.xml
    jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
    jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/commit/AnnotatingConflictHandler.java Tue Apr 23 17:06:54 2013
@@ -18,14 +18,11 @@ package org.apache.jackrabbit.oak.plugin
 
 import java.util.List;
 
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.spi.commit.ConflictHandler;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
-import static com.google.common.collect.Iterables.addAll;
 import static com.google.common.collect.Lists.newArrayList;
 import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
@@ -120,19 +117,8 @@ public class AnnotatingConflictHandler i
     }
 
     private static NodeBuilder addConflictMarker(NodeBuilder parent) {
-        List<String> mixins = newArrayList();;
-        boolean hasConflictType = false;
-        Iterable<String> types = parent.getNames(JCR_MIXINTYPES);
-        if (types != null) {
-            for (String type : types) {
-                mixins.add(type);
-                if (MIX_REP_MERGE_CONFLICT.equals(type)) {
-                    hasConflictType = true;
-                }
-            }
-        }
-        if (!hasConflictType) {
-            mixins.add(MIX_REP_MERGE_CONFLICT);
+        List<String> mixins = newArrayList(parent.getNames(JCR_MIXINTYPES));
+        if (mixins.add(MIX_REP_MERGE_CONFLICT)) {
             parent.setProperty(JCR_MIXINTYPES, mixins, NAMES);
         }
         return parent.child(REP_OURS);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/IndexUtils.java Tue Apr 23 17:06:54 2013
@@ -35,8 +35,8 @@ import static org.apache.jackrabbit.JcrC
 import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
 import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
 import static org.apache.jackrabbit.oak.api.Type.NAME;
+import static org.apache.jackrabbit.oak.api.Type.NAMES;
 import static org.apache.jackrabbit.oak.api.Type.STRING;
-import static org.apache.jackrabbit.oak.api.Type.STRINGS;
 import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.DECLARING_NODE_TYPES;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
@@ -89,9 +89,9 @@ public class IndexUtils {
         if (unique) {
             entry.setProperty(UNIQUE_PROPERTY_NAME, unique);
         }
-        entry.setProperty(PropertyStates.createProperty(PROPERTY_NAMES, propertyNames, STRINGS));
+        entry.setProperty(PropertyStates.createProperty(PROPERTY_NAMES, propertyNames, NAMES));
         if (declaringNodeTypeNames != null && !declaringNodeTypeNames.isEmpty()) {
-            entry.setProperty(PropertyStates.createProperty(DECLARING_NODE_TYPES, declaringNodeTypeNames, STRINGS));
+            entry.setProperty(PropertyStates.createProperty(DECLARING_NODE_TYPES, declaringNodeTypeNames, NAMES));
         }
         return entry;
     }
@@ -119,7 +119,7 @@ public class IndexUtils {
         if (declaringNodeTypeNames != null && declaringNodeTypeNames.length > 0) {
             entry.setStrings(DECLARING_NODE_TYPES, declaringNodeTypeNames);
         }
-        entry.setStrings(PROPERTY_NAMES, propertyNames);
+        entry.setNames(PROPERTY_NAMES, propertyNames);
     }
 
     /**

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndex.java Tue Apr 23 17:06:54 2013
@@ -57,7 +57,7 @@ class NodeTypeIndex implements QueryInde
         }
         NodeTypeIndexLookup lookup = new NodeTypeIndexLookup(root);
         if (lookup.isIndexed(filter.getPath())) {
-            return lookup.getCost(resolveNodeType(root, filter.getNodeType()));
+            return lookup.getCost(filter);
         } else {
             return Double.POSITIVE_INFINITY;
         }
@@ -70,13 +70,12 @@ class NodeTypeIndex implements QueryInde
             throw new IllegalStateException(
                     "NodeType index is used even when no index is available for filter " + filter);
         }
-        return Cursors.newPathCursorDistinct(lookup.query(
-                filter, resolveNodeType(root, filter.getNodeType())));
+        return Cursors.newPathCursorDistinct(lookup.query(filter));
     }
     
     @Override
     public String getPlan(Filter filter, NodeState root) {
-        return "nodeType " + filter.getNodeType() + " path " + filter.getPath();
+        return filter.toString();
     }
 
     @Override
@@ -87,43 +86,7 @@ class NodeTypeIndex implements QueryInde
     //----------------------------< internal >----------------------------------
 
     private static boolean hasNodeTypeRestriction(Filter filter) {
-        return filter.getNodeType() != null
-                && !filter.getNodeType().equals(NT_BASE);
+        return !filter.matchesAllTypes();
     }
 
-    private static Iterable<String> resolveNodeType(NodeState root, String nodeType) {
-        ReadOnlyNodeTypeManager ntMgr = new NTManager(root);
-        Set<String> ntNames = Sets.newHashSet();
-        try {
-            NodeType nt = ntMgr.getNodeType(nodeType);
-            for (NodeTypeIterator types = nt.getSubtypes(); types.hasNext();) {
-                ntNames.add(types.nextNodeType().getName());
-            }
-            ntNames.add(nodeType);
-        } catch (RepositoryException e) {
-            // unknown node type
-        }
-        return ntNames;
-    }
-
-    private static final class NTManager extends ReadOnlyNodeTypeManager {
-
-        private final NodeState root;
-
-        NTManager(NodeState root) {
-            this.root = root;
-        }
-
-        @Override
-        protected Tree getTypes() {
-            Tree t = new ReadOnlyTree(root);
-            for (String name : PathUtils.elements(NodeTypeConstants.NODE_TYPES_PATH)) {
-                t = t.getChild(name);
-                if (t == null) {
-                    break;
-                }
-            }
-            return t;
-        }
-    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexLookup.java Tue Apr 23 17:06:54 2013
@@ -16,11 +16,11 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.nodetype;
 
+import static org.apache.jackrabbit.oak.spi.query.PropertyValues.newName;
+
 import org.apache.jackrabbit.JcrConstants;
-import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexLookup;
 import org.apache.jackrabbit.oak.spi.query.Filter;
-import org.apache.jackrabbit.oak.spi.query.PropertyValues;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 import com.google.common.collect.Iterables;
@@ -65,11 +65,10 @@ class NodeTypeIndexLookup implements Jcr
                 path.substring(slash));
     }
 
-    public double getCost(Iterable<String> nodeTypes) {
-        PropertyValue ntNames = PropertyValues.newName(nodeTypes);
+    public double getCost(Filter filter) {
         Property2IndexLookup lookup = new Property2IndexLookup(root);
-        return lookup.getCost(null, JCR_PRIMARYTYPE, ntNames)
-                + lookup.getCost(null, JCR_MIXINTYPES, ntNames);
+        return lookup.getCost(null, JCR_PRIMARYTYPE, newName(filter.getPrimaryTypes()))
+                + lookup.getCost(null, JCR_MIXINTYPES, newName(filter.getMixinTypes()));
     }
 
     /**
@@ -79,12 +78,11 @@ class NodeTypeIndexLookup implements Jcr
      * @param nodeTypes the names of the node types to match.
      * @return the matched paths (the result might contain duplicate entries)
      */
-    public Iterable<String> query(Filter filter, Iterable<String> nodeTypes) {
-        final PropertyValue ntNames = PropertyValues.newName(nodeTypes);
+    public Iterable<String> query(Filter filter) {
         Property2IndexLookup lookup = new Property2IndexLookup(root);
         return Iterables.concat(
-                lookup.query(filter, JCR_PRIMARYTYPE, ntNames),
-                lookup.query(filter, JCR_MIXINTYPES, ntNames));
+                lookup.query(filter, JCR_PRIMARYTYPE, newName(filter.getPrimaryTypes())),
+                lookup.query(filter, JCR_MIXINTYPES, newName(filter.getMixinTypes())));
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexLookup.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexLookup.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexLookup.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexLookup.java Tue Apr 23 17:06:54 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.p2;
 
+import static com.google.common.collect.Iterables.contains;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.DECLARING_NODE_TYPES;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.PROPERTY_NAMES;
@@ -24,6 +25,7 @@ import static org.apache.jackrabbit.oak.
 
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import javax.annotation.Nullable;
 
@@ -76,13 +78,19 @@ public class Property2IndexLookup {
      * @return true if the property is indexed
      */
     public boolean isIndexed(String propertyName, String path, Filter filter) {
+        Set<String> supertypes = null;
+        if (filter != null && !filter.matchesAllTypes()) {
+            supertypes = filter.getSupertypes();
+        }
+
         if (PathUtils.denotesRoot(path)) {
-            return getIndexDataNode(root, propertyName, filter) != null;
+            return getIndexDataNode(root, propertyName, supertypes) != null;
         }
+
         NodeState node = root;
         Iterator<String> it = PathUtils.elements(path).iterator();
         while (it.hasNext()) {
-            if (getIndexDataNode(node, propertyName, filter) != null) {
+            if (getIndexDataNode(node, propertyName, supertypes) != null) {
                 return true;
             }
             node = node.getChildNode(it.next());
@@ -91,7 +99,12 @@ public class Property2IndexLookup {
     }
 
     public Iterable<String> query(Filter filter, String propertyName, PropertyValue value) {
-        NodeState state = getIndexDataNode(root, propertyName, filter);
+        Set<String> supertypes = null;
+        if (filter != null && !filter.matchesAllTypes()) {
+            supertypes = filter.getSupertypes();
+        }
+
+        NodeState state = getIndexDataNode(root, propertyName, supertypes);
         if (state == null) {
             throw new IllegalArgumentException("No index for " + propertyName);
         }
@@ -100,7 +113,12 @@ public class Property2IndexLookup {
     }
 
     public double getCost(Filter filter, String name, PropertyValue value) {
-        NodeState state = getIndexDataNode(root, name, filter);
+        Set<String> supertypes = null;
+        if (filter != null && !filter.matchesAllTypes()) {
+            supertypes = filter.getSupertypes();
+        }
+
+        NodeState state = getIndexDataNode(root, name, supertypes);
         if (state == null) {
             return Double.POSITIVE_INFINITY;
         }
@@ -113,54 +131,41 @@ public class Property2IndexLookup {
      * applicable index with data.
      * 
      * @param propertyName the property name
-     * @param filter for the node type restriction (null if no node type restriction)
+     * @param supertypes the filter node type and all its supertypes,
+     *                   or {@code null} if the filter matches all types
      * @return the node where the index data is stored, or null if no index
      *         definition or index data node was found
      */
     @Nullable
-    private static NodeState getIndexDataNode(NodeState node, String propertyName, Filter filter) {
-        NodeState state = node.getChildNode(INDEX_DEFINITIONS_NAME);
-        if (!state.exists()) {
-            return null;
-        }
-        String filterNodeType = null;
-        if (filter != null) {
-            filterNodeType = filter.getNodeType();
-        }
+    private NodeState getIndexDataNode(
+            NodeState node, String propertyName, Set<String> supertypes) {
         //keep a fallback to a matching index def that has *no* node type constraints
         NodeState fallback = null;
+
+        NodeState state = node.getChildNode(INDEX_DEFINITIONS_NAME);
         for (ChildNodeEntry entry : state.getChildNodeEntries()) {
             NodeState ns = entry.getNodeState();
             PropertyState type = ns.getProperty(TYPE_PROPERTY_NAME);
             if (type == null || type.isArray() || !TYPE.equals(type.getValue(Type.STRING))) {
                 continue;
             }
-            if (containsValue(ns.getProperty(PROPERTY_NAMES), propertyName)) {
-                if (filterNodeType == null
-                        || containsValue(ns.getProperty(DECLARING_NODE_TYPES),
-                                filterNodeType)) {
-                    return ns.getChildNode(":index");
-                }
-                if (ns.getProperty(DECLARING_NODE_TYPES) == null) {
-                    fallback = ns.getChildNode(":index");
+            if (contains(ns.getNames(PROPERTY_NAMES), propertyName)) {
+                NodeState index = ns.getChildNode(":index");
+                if (ns.hasProperty(DECLARING_NODE_TYPES) && supertypes != null) {
+                    for (String typeName : ns.getNames(DECLARING_NODE_TYPES)) {
+                        if (supertypes.contains(typeName)) {
+                            // TODO: prefer the most specific type restriction
+                            return index;
+                        }
+                    }
+                } else if (supertypes == null) {
+                    return index;
+                } else if (fallback == null) {
+                    fallback = index;
                 }
             }
         }
         return fallback;
     }
 
-    private static boolean containsValue(PropertyState values, String lookup) {
-        if (values == null) {
-            return false;
-        }
-        if (values.isArray()) {
-            for (String v : values.getValue(Type.STRINGS)) {
-                if (lookup.equals(v)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-        return lookup.equals(values.getValue(Type.STRING));
-    }
-}
\ No newline at end of file
+}

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyNodeState.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/EmptyNodeState.java Tue Apr 23 17:06:54 2013
@@ -18,8 +18,7 @@ package org.apache.jackrabbit.oak.plugin
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Collections;
+import static java.util.Collections.emptyList;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
@@ -76,14 +75,14 @@ public final class EmptyNodeState implem
         return null;
     }
 
-    @Override @CheckForNull
+    @Override @Nonnull
     public Iterable<String> getNames(@Nonnull String name) {
-        return null;
+        return emptyList();
     }
 
     @Override @Nonnull
     public Iterable<? extends PropertyState> getProperties() {
-        return Collections.emptyList();
+        return emptyList();
     }
 
     @Override
@@ -105,12 +104,12 @@ public final class EmptyNodeState implem
 
     @Override
     public Iterable<String> getChildNodeNames() {
-        return Collections.emptyList();
+        return emptyList();
     }
 
     @Override @Nonnull
     public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
-        return Collections.emptyList();
+        return emptyList();
     }
 
     @Override @Nonnull

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java Tue Apr 23 17:06:54 2013
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.plugin
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.Maps.newHashMap;
+import static java.util.Collections.emptyList;
 import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
 import static org.apache.jackrabbit.oak.api.Type.NAME;
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
@@ -447,13 +448,13 @@ public class MemoryNodeBuilder implement
         }
     }
 
-    @Override @CheckForNull
+    @Override @Nonnull
     public Iterable<String> getNames(@Nonnull String name) {
         PropertyState property = getProperty(name);
         if (property != null && property.getType() == NAMES) {
             return property.getValue(NAMES);
         } else {
-            return null;
+            return emptyList();
         }
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/NodeTypeConstants.java Tue Apr 23 17:06:54 2013
@@ -61,7 +61,8 @@ public interface NodeTypeConstants exten
 
     // Precompiled Oak type information fields
     String OAK_SUPERTYPES = "oak:supertypes";
-    String OAK_SUBTYPES = "oak:subtypes";
+    String OAK_PRIMARY_SUBTYPES = "oak:primarySubtypes";
+    String OAK_MIXIN_SUBTYPES = "oak:mixinSubtypes";
     String OAK_MANDATORY_PROPERTIES = "oak:mandatoryProperties";
     String OAK_MANDATORY_CHILD_NODES = "oak:mandatoryChildNodes";
     String OAK_NAMED_SINGLE_VALUED_PROPERTIES =

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/RegistrationEditor.java Tue Apr 23 17:06:54 2013
@@ -46,13 +46,14 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_CHILD_NODE_DEFINITIONS;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_MANDATORY_CHILD_NODES;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_MANDATORY_PROPERTIES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_MIXIN_SUBTYPES;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_CHILD_NODE_DEFINITIONS;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_SINGLE_VALUED_PROPERTIES;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_PROPERTY_DEFINITIONS;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_PROPERTY_DEFINITIONS;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_RESIDUAL_CHILD_NODE_DEFINITIONS;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_RESIDUAL_PROPERTY_DEFINITIONS;
-import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_SUBTYPES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_PRIMARY_SUBTYPES;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_SUPERTYPES;
 
 import java.util.Collections;
@@ -220,7 +221,7 @@ class RegistrationEditor extends Default
         Iterable<String> empty = emptyList();
         type.setProperty(JCR_PRIMARYTYPE, "oak:nodeType", NAME);
         type.removeProperty(OAK_SUPERTYPES);
-        type.setProperty(OAK_SUBTYPES, empty, NAMES);
+        type.setProperty(OAK_PRIMARY_SUBTYPES, empty, NAMES);
         type.setProperty(OAK_MANDATORY_PROPERTIES, empty, NAMES);
         type.setProperty(OAK_MANDATORY_CHILD_NODES, empty, NAMES);
         type.setProperty(OAK_NAMED_SINGLE_VALUED_PROPERTIES, empty, NAMES);
@@ -363,8 +364,12 @@ class RegistrationEditor extends Default
             }
             for (String name : types.getChildNodeNames()) {
                 NodeBuilder type = types.child(name);
+                String listName = OAK_PRIMARY_SUBTYPES;
+                if (type.getBoolean(JCR_ISMIXIN)) {
+                    listName = OAK_MIXIN_SUBTYPES;
+                }
                 for (String supername : getNames(type, OAK_SUPERTYPES)) {
-                    addNameToList(types.child(supername), OAK_SUBTYPES, name);
+                    addNameToList(types.child(supername), listName, name);
                 }
             }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java Tue Apr 23 17:06:54 2013
@@ -18,12 +18,7 @@ package org.apache.jackrabbit.oak.query;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Maps.newHashMap;
-import static org.apache.jackrabbit.JcrConstants.NT_BASE;
-import static org.apache.jackrabbit.oak.api.Type.NAMES;
-import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_SINGLE_VALUED_PROPERTIES;
-import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_SUBTYPES;
 
-import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -47,8 +42,6 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.ImmutableSet;
-
 import javax.jcr.PropertyType;
 import java.math.BigDecimal;
 import java.text.ParseException;
@@ -56,7 +49,6 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * The SQL2 parser can convert a JCR-SQL2 query to a query. The 'old' SQL query
@@ -194,31 +186,17 @@ public class SQL2Parser {
 
     private SelectorImpl parseSelector() throws ParseException {
         String nodeTypeName = readName();
-
-        Set<String> matchingTypes = null;
-        if (!NT_BASE.equals(nodeTypeName)) {
-            ImmutableSet.Builder<String> builder = ImmutableSet.builder();
-            NodeState type = types.getChildNode(nodeTypeName);
-            if (type.exists()) {
-                builder.add(nodeTypeName);
-                PropertyState subtypes = type.getProperty(OAK_SUBTYPES);
-                if (subtypes != null) {
-                    for (String subname : subtypes.getValue(NAMES)) {
-                        builder.add(subname);
-                    }
-                }
-            } else {
-                throw getSyntaxError("unknown node type");
-            }
-            matchingTypes = builder.build();
+        NodeState type = types.getChildNode(nodeTypeName);
+        if (!type.exists()) {
+            throw getSyntaxError("unknown node type");
         }
 
+        String selectorName = nodeTypeName;
         if (readIf("AS")) {
-            String selectorName = readName();
-            return factory.selector(nodeTypeName, selectorName, matchingTypes);
-        } else {
-            return factory.selector(nodeTypeName, nodeTypeName, matchingTypes);
+            selectorName = readName();
         }
+
+        return factory.selector(type, selectorName);
     }
 
     private String readName() throws ParseException {
@@ -816,19 +794,13 @@ public class SQL2Parser {
     private void addWildcardColumns(
             Collection<ColumnImpl> columns, SelectorImpl selector,
             boolean includeSelectorName) {
-        String name = selector.getNodeTypeName();
-
-        PropertyState properties = types.getChildNode(name).getProperty(
-                OAK_NAMED_SINGLE_VALUED_PROPERTIES);
-        if (properties != null) {
-            String selectorName = selector.getSelectorName();
-            for (String property : properties.getValue(NAMES)) {
-                String columnName = property;
-                if (includeSelectorName) {
-                    columnName = selectorName + "." + property;
-                }
-                columns.add(factory.column(selectorName, property, columnName));
+        String selectorName = selector.getSelectorName();
+        for (String property : selector.getWildcardColumns()) {
+            String columnName = property;
+            if (includeSelectorName) {
+                columnName = selectorName + "." + property;
             }
+            columns.add(factory.column(selectorName, property, columnName));
         }
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java Tue Apr 23 17:06:54 2013
@@ -13,9 +13,8 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
-import java.util.Set;
-
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 /**
  * A factory for syntax tree elements.
@@ -130,10 +129,8 @@ public class AstElementFactory {
         return new SameNodeJoinConditionImpl(selector1Name, selector2Name, selector2Path);
     }
 
-    public SelectorImpl selector(
-            String nodeTypeName, String selectorName,
-            Set<String> matchingTypes) {
-        return new SelectorImpl(nodeTypeName, selectorName, matchingTypes);
+    public SelectorImpl selector(NodeState type, String selectorName) {
+        return new SelectorImpl(type, selectorName);
     }
 
     public UpperCaseImpl upperCase(DynamicOperandImpl operand) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java Tue Apr 23 17:06:54 2013
@@ -19,14 +19,23 @@
 package org.apache.jackrabbit.oak.query.ast;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Sets.newHashSet;
+import static org.apache.jackrabbit.JcrConstants.JCR_ISMIXIN;
 import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
+import static org.apache.jackrabbit.JcrConstants.JCR_NODETYPENAME;
 import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.JcrConstants.NT_BASE;
 import static org.apache.jackrabbit.oak.api.Type.NAME;
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_MIXIN_SUBTYPES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_NAMED_SINGLE_VALUED_PROPERTIES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_PRIMARY_SUBTYPES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.OAK_SUPERTYPES;
 
 import java.util.Set;
 
-import org.apache.jackrabbit.JcrConstants;
+import javax.annotation.Nonnull;
+
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Tree;
@@ -48,14 +57,19 @@ public class SelectorImpl extends Source
     // TODO possibly support using multiple indexes (using index intersection / index merge)
     protected QueryIndex index;
 
-    private final String nodeTypeName;
+    private final NodeState nodeType;
 
     private final String selectorName;
 
-    /**
-     * Names of matching node types, or {@code null} if all types match.
-     */
-    private final Set<String> matchingTypes;
+    private final String nodeTypeName;
+
+    private final boolean matchesAllTypes;
+
+    private final Set<String> supertypes;
+
+    private final Set<String> primaryTypes;
+
+    private final Set<String> mixinTypes;
 
     private Cursor cursor;
     private IndexRow currentRow;
@@ -70,22 +84,52 @@ public class SelectorImpl extends Source
      */
     private ConstraintImpl selectorCondition;
 
-    public SelectorImpl(
-            String nodeTypeName, String selectorName,
-            Set<String> matchingTypes) {
-        this.nodeTypeName = checkNotNull(nodeTypeName);
+    public SelectorImpl(NodeState nodeType, String selectorName) {
+        this.nodeType = checkNotNull(nodeType);
         this.selectorName = checkNotNull(selectorName);
-        this.matchingTypes = matchingTypes;
-    }
 
-    public String getNodeTypeName() {
-        return nodeTypeName;
+        this.nodeTypeName = nodeType.getName(JCR_NODETYPENAME);
+        this.matchesAllTypes = NT_BASE.equals(nodeTypeName);
+
+        this.supertypes = newHashSet(nodeType.getNames(OAK_SUPERTYPES));
+        supertypes.add(nodeTypeName);
+
+        this.primaryTypes = newHashSet(nodeType.getNames(OAK_PRIMARY_SUBTYPES));
+        this.mixinTypes = newHashSet(nodeType.getNames(OAK_MIXIN_SUBTYPES));
+        if (nodeType.getBoolean(JCR_ISMIXIN)) {
+            mixinTypes.add(nodeTypeName);
+        } else {
+            primaryTypes.add(nodeTypeName);
+        }
     }
 
     public String getSelectorName() {
         return selectorName;
     }
 
+    public boolean matchesAllTypes() {
+        return matchesAllTypes;
+    }
+
+    @Nonnull
+    public Set<String> getSupertypes() {
+        return supertypes;
+    }
+
+    @Nonnull
+    public Set<String> getPrimaryTypes() {
+        return primaryTypes;
+    }
+
+    @Nonnull
+    public Set<String> getMixinTypes() {
+        return mixinTypes;
+    }
+
+    public Iterable<String> getWildcardColumns() {
+        return nodeType.getNames(OAK_NAMED_SINGLE_VALUED_PROPERTIES);
+    }
+
     @Override
     boolean accept(AstVisitor v) {
         return v.visit(this);
@@ -93,6 +137,7 @@ public class SelectorImpl extends Source
 
     @Override
     public String toString() {
+        String nodeTypeName = nodeType.getName(JCR_NODETYPENAME);
         return quote(nodeTypeName) + " as " + quote(selectorName);
     }
 
@@ -139,7 +184,6 @@ public class SelectorImpl extends Source
     private Filter createFilter(boolean preparing) {
         FilterImpl f = new FilterImpl(this, query.getStatement());
         f.setPreparing(preparing);
-        f.setNodeType(nodeTypeName);
         if (joinCondition != null) {
             joinCondition.restrict(f);
         }
@@ -169,9 +213,7 @@ public class SelectorImpl extends Source
             if (tree == null) {
                 continue;
             }
-            if (nodeTypeName != null
-                    && !nodeTypeName.equals(JcrConstants.NT_BASE)
-                    && !evaluateTypeMatch(tree)) {
+            if (!matchesAllTypes && !evaluateTypeMatch(tree)) {
                 continue;
             }
             if (selectorCondition != null && !selectorCondition.evaluate()) {
@@ -188,14 +230,10 @@ public class SelectorImpl extends Source
     }
 
     private boolean evaluateTypeMatch(Tree tree) {
-        if (matchingTypes == null) {
-            return true; // shortcut for a common case
-        }
-
         PropertyState primary = tree.getProperty(JCR_PRIMARYTYPE);
         if (primary != null && primary.getType() == NAME) {
             String name = primary.getValue(NAME);
-            if (matchingTypes.contains(name)) {
+            if (primaryTypes.contains(name)) {
                 return true;
             }
         }
@@ -203,7 +241,7 @@ public class SelectorImpl extends Source
         PropertyState mixins = tree.getProperty(JCR_MIXINTYPES);
         if (mixins != null && mixins.getType() == NAMES) {
             for (String name : mixins.getValue(NAMES)) {
-                if (matchingTypes.contains(name)) {
+                if (mixinTypes.contains(name)) {
                     return true;
                 }
             }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java Tue Apr 23 17:06:54 2013
@@ -24,8 +24,9 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map.Entry;
+import java.util.Set;
 
-import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.jcr.PropertyType;
 
@@ -60,11 +61,6 @@ public class FilterImpl implements Filte
     private PathRestriction pathRestriction = PathRestriction.NO_RESTRICTION;
 
     /**
-     *  The node type, or null if not set.
-     */
-    private String nodeType;
-
-    /**
      * The fulltext search conditions, if any.
      */
     private final ArrayList<String> fulltextConditions = new ArrayList<String>();
@@ -116,16 +112,6 @@ public class FilterImpl implements Filte
         this.path = path;
     }
 
-    @Override
-    @CheckForNull
-    public String getNodeType() {
-        return nodeType;
-    }
-
-    public void setNodeType(String nodeType) {
-        this.nodeType = nodeType;
-    }
-
     public boolean isDistinct() {
         return distinct;
     }
@@ -136,7 +122,6 @@ public class FilterImpl implements Filte
 
     public void setAlwaysFalse() {
         propertyRestrictions.clear();
-        nodeType = "";
         path = "/";
         pathRestriction = PathRestriction.EXACT;
         alwaysFalse = true;
@@ -152,6 +137,26 @@ public class FilterImpl implements Filte
     }
 
     @Override
+    public boolean matchesAllTypes() {
+        return selector.matchesAllTypes();
+    }
+
+    @Override @Nonnull
+    public Set<String> getSupertypes() {
+        return selector.getSupertypes();
+    }
+
+    @Override @Nonnull
+    public Set<String> getPrimaryTypes() {
+        return selector.getPrimaryTypes();
+    }
+
+    @Override @Nonnull
+    public Set<String> getMixinTypes() {
+        return selector.getMixinTypes();
+    }
+
+    @Override
     public Collection<PropertyRestriction> getPropertyRestrictions() {
         return propertyRestrictions.values();
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Filter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Filter.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Filter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Filter.java Tue Apr 23 17:06:54 2013
@@ -19,8 +19,9 @@
 package org.apache.jackrabbit.oak.spi.query;
 
 import java.util.Collection;
+import java.util.Set;
 
-import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.jcr.PropertyType;
 
@@ -76,13 +77,44 @@ public interface Filter {
     String getPath();
 
     /**
+     * Checks whether nodes of all types can match this filter.
+     *
+     * @return {@code true} iff there are no type restrictions
+     */
+    boolean matchesAllTypes();
+
+    /**
+     * Returns the names of the filter node type and all its supertypes.
+     *
+     * @return supertype name
+     */
+    @Nonnull
+    Set<String> getSupertypes();
+
+    /**
+     * Returns the names of all matching primary node types.
+     *
+     * @return primary node type names
+     */
+    @Nonnull
+    Set<String> getPrimaryTypes();
+
+    /**
+     * Returns the names of all matching mixin node types.
+     *
+     * @return mixin node type names
+     */
+    @Nonnull
+    Set<String> getMixinTypes();
+
+    /**
      * Get the node type.
      * 
      * @return the node type restriction or <code>null</code> if none is set.
      */
-    @CheckForNull
-    String getNodeType();
-    
+//    @CheckForNull
+//    String getNodeType();
+
     /**
      * Get the complete query statement. The statement should only be used for
      * logging purposes.

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeState.java Tue Apr 23 17:06:54 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.oak.spi.state;
 
+import static java.util.Collections.emptyList;
 import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
 import static org.apache.jackrabbit.oak.api.Type.NAME;
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
@@ -70,13 +71,13 @@ public abstract class AbstractNodeState 
         }
     }
 
-    @Override @CheckForNull
+    @Override @Nonnull
     public Iterable<String> getNames(@Nonnull String name) {
         PropertyState property = getProperty(name);
         if (property != null && property.getType() == NAMES) {
             return property.getValue(NAMES);
         } else {
-            return null;
+            return emptyList();
         }
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java Tue Apr 23 17:06:54 2013
@@ -211,14 +211,14 @@ public interface NodeBuilder {
      * if (property != null && property.getType() == Type.NAMES) {
      *     return property.getValue(Type.NAMES);
      * } else {
-     *     return null;
+     *     return Collections.emptyList();
      * }
      * </pre>
      *
      * @param name property name
-     * @return name values of the named property, or {@code null}
+     * @return name values of the named property, or an empty collection
      */
-    @CheckForNull
+    @Nonnull
     Iterable<String> getNames(@Nonnull String name);
 
     /**

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeState.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeState.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeState.java Tue Apr 23 17:06:54 2013
@@ -194,14 +194,14 @@ public interface NodeState {
      * if (property != null && property.getType() == Type.NAMES) {
      *     return property.getValue(Type.NAMES);
      * } else {
-     *     return null;
+     *     return Collections.emptyList();
      * }
      * </pre>
      *
      * @param name property name
-     * @return name values of the named property, or {@code null}
+     * @return name values of the named property, or an empty collection
      */
-    @CheckForNull
+    @Nonnull
     Iterable<String> getNames(@Nonnull String name);
 
     /**

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java Tue Apr 23 17:06:54 2013
@@ -128,7 +128,7 @@ public class ReadOnlyBuilder implements 
         return state.getName(name);
     }
 
-    @Override @CheckForNull
+    @Override @Nonnull
     public Iterable<String> getNames(@Nonnull String name) {
         return state.getNames(name);
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd Tue Apr 23 17:06:54 2013
@@ -427,7 +427,8 @@
 
 [oak:nodeType] > nt:nodeType
   - oak:supertypes (NAME) protected multiple autocreated
-  - oak:subtypes (NAME) protected multiple autocreated
+  - oak:primarySubtypes (NAME) protected multiple autocreated
+  - oak:mixinSubtypes (NAME) protected multiple autocreated
   - oak:mandatoryProperties (NAME) protected multiple autocreated
   - oak:mandatoryChildNodes (NAME) protected multiple autocreated
   - oak:namedSingleValuedProperties (NAME) protected multiple autocreated

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/IndexHookManagerTest.java Tue Apr 23 17:06:54 2013
@@ -16,9 +16,12 @@
  */
 package org.apache.jackrabbit.oak.plugins.index;
 
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.JcrConstants.NT_BASE;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.IndexUtils.createIndexDefinition;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -30,7 +33,11 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexHookProvider;
 import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexLookup;
+import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
+import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.commit.EditorHook;
+import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -41,6 +48,10 @@ import com.google.common.collect.Sets;
 
 public class IndexHookManagerTest {
 
+    private NodeState root = new InitialContent().initialize(EMPTY_NODE);
+
+    private NodeBuilder builder = root.builder();
+
     /**
      * Simple Test
      * <ul>
@@ -52,10 +63,6 @@ public class IndexHookManagerTest {
      */
     @Test
     public void test() throws Exception {
-        NodeState root = EMPTY_NODE;
-
-        NodeBuilder builder = root.builder();
-
         createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
                 false, ImmutableSet.of("foo"), null);
         createIndexDefinition(
@@ -92,12 +99,6 @@ public class IndexHookManagerTest {
 
     }
 
-    private static Set<String> find(Property2IndexLookup lookup, String name,
-            String value) {
-        return Sets.newHashSet(lookup.query(null, name,
-                PropertyValues.newString(value)));
-    }
-
     /**
      * Reindex Test
      * <ul>
@@ -108,10 +109,6 @@ public class IndexHookManagerTest {
      */
     @Test
     public void testReindex() throws Exception {
-        NodeState root = EMPTY_NODE;
-
-        NodeBuilder builder = root.builder();
-
         builder.child("testRoot").setProperty("foo", "abc");
         NodeState before = builder.getNodeState();
         createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
@@ -146,10 +143,6 @@ public class IndexHookManagerTest {
      */
     @Test
     public void testReindex2() throws Exception {
-        NodeState root = EMPTY_NODE;
-
-        NodeBuilder builder = root.builder();
-
         builder.child("testRoot").setProperty("foo", "abc");
         NodeState before = builder.getNodeState();
 
@@ -185,9 +178,6 @@ public class IndexHookManagerTest {
      */
     @Test
     public void testReindex3() throws Exception {
-        NodeState root = EMPTY_NODE;
-
-        NodeBuilder builder = root.builder();
         builder.child("testRoot").setProperty("foo", "abc");
 
         createIndexDefinition(builder.child("oak:index"), "rootIndex", true,
@@ -217,9 +207,6 @@ public class IndexHookManagerTest {
 
     @Test
     public void testIndexDefinitions() throws Exception {
-        NodeState root = EMPTY_NODE;
-
-        NodeBuilder builder = root.builder();
         createIndexDefinition(builder.child("oak:index"), "existing", true,
                 false, ImmutableSet.of("foo"), null);
 
@@ -243,6 +230,17 @@ public class IndexHookManagerTest {
                 ":index");
     }
 
+    private Set<String> find(Property2IndexLookup lookup, String name,
+            String value) {
+        NodeState system = root.getChildNode(JCR_SYSTEM);
+        NodeState types = system.getChildNode(JCR_NODE_TYPES);
+        NodeState type = types.getChildNode(NT_BASE);
+        SelectorImpl selector = new SelectorImpl(type, NT_BASE);
+        Filter filter = new FilterImpl(selector, "SELECT * FROM [nt:base]");
+        return Sets.newHashSet(lookup.query(filter, name,
+                PropertyValues.newString(value)));
+    }
+
     private static NodeState checkPathExists(NodeState state, String... verify) {
         NodeState c = state;
         for (String p : verify) {

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/nodetype/NodeTypeIndexTest.java Tue Apr 23 17:06:54 2013
@@ -33,6 +33,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.IndexHookProvider;
 import org.apache.jackrabbit.oak.plugins.index.p2.Property2IndexHookProvider;
 import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
+import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.commit.EditorHook;
 import org.apache.jackrabbit.oak.spi.lifecycle.OakInitializer;
@@ -46,6 +47,8 @@ import org.junit.Test;
 
 import com.google.common.collect.Sets;
 
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -81,23 +84,29 @@ public class NodeTypeIndexTest {
 
         NodeState rootState = store.getRoot();
         NodeTypeIndex index = new NodeTypeIndex();
-        FilterImpl filter = new FilterImpl(null, null);
+        FilterImpl filter;
 
-        filter.setNodeType(JcrConstants.NT_FOLDER);
-        // note on cost: this is currently twice the number of matches
-        // because jcr:primaryType and jcr:mixinTypes are indexed together
-        assertEquals(4.0, index.getCost(filter, rootState), 0.0);
+        filter = createFilter(rootState, JcrConstants.NT_FOLDER);
+        assertEquals(2.0, index.getCost(filter, rootState), 0.0);
         checkCursor(index.query(filter, rootState), "/folder-1", "/folder-2");
 
-        filter.setNodeType(JcrConstants.NT_FILE);
-        assertEquals(2.0, index.getCost(filter, rootState), 0.0);
+        filter = createFilter(rootState, JcrConstants.NT_FILE);
+        assertEquals(1.0, index.getCost(filter, rootState), 0.0);
         checkCursor(index.query(filter, rootState), "/file-1");
 
-        filter.setNodeType(JcrConstants.NT_HIERARCHYNODE);
-        assertEquals(6.0, index.getCost(filter, rootState), 0.0);
+        filter = createFilter(rootState, JcrConstants.NT_HIERARCHYNODE);
+        assertEquals(3.0, index.getCost(filter, rootState), 0.0);
         checkCursor(index.query(filter, rootState), "/folder-1", "/folder-2", "/file-1");
     }
 
+    private static FilterImpl createFilter(NodeState root, String nodeTypeName) {
+        NodeState system = root.getChildNode(JCR_SYSTEM);
+        NodeState types = system.getChildNode(JCR_NODE_TYPES);
+        NodeState type = types.getChildNode(nodeTypeName);
+        SelectorImpl selector = new SelectorImpl(type, nodeTypeName);
+        return new FilterImpl(selector, "SELECT * FROM [" + nodeTypeName + "]");
+    }
+
     private void checkCursor(Cursor cursor, String... matches) {
         // make sure the index is actually used
         // and does not traverse

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2IndexTest.java Tue Apr 23 17:06:54 2013
@@ -16,7 +16,12 @@
  */
 package org.apache.jackrabbit.oak.plugins.index.p2;
 
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.JcrConstants.NT_BASE;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -26,10 +31,10 @@ import java.util.Set;
 
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
+import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
-import org.apache.jackrabbit.oak.spi.commit.Editor;
-import org.apache.jackrabbit.oak.spi.commit.EditorHook;
-import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.commit.EditorDiff;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -48,7 +53,7 @@ public class Property2IndexTest {
 
     @Test
     public void testPropertyLookup() throws Exception {
-        NodeState root = EMPTY_NODE;
+        NodeState root = new InitialContent().initialize(EMPTY_NODE);
 
         // Add index definition
         NodeBuilder builder = root.builder();
@@ -56,7 +61,7 @@ public class Property2IndexTest {
                 .child("foo")
                 .setProperty("jcr:primaryType", "oak:queryIndexDefinition",
                         Type.NAME).setProperty("type", "p2")
-                .setProperty("propertyNames", "foo");
+                .setProperty("propertyNames", Arrays.asList("foo"), Type.NAMES);
         NodeState before = builder.getNodeState();
 
         // Add some content and process it through the property index hook
@@ -70,28 +75,23 @@ public class Property2IndexTest {
         }
         NodeState after = builder.getNodeState();
 
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new Property2IndexHook(builder);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
-        NodeState indexed = hook.processCommit(before, after);
+        EditorDiff.process(new Property2IndexHook(builder), before, after);
+        NodeState indexed = builder.getNodeState();
+
+        FilterImpl f = createFilter(indexed, NT_BASE);
 
         // Query the index
         Property2IndexLookup lookup = new Property2IndexLookup(indexed);
-        assertEquals(ImmutableSet.of("a", "b"), find(lookup, "foo", "abc"));
-        assertEquals(ImmutableSet.of("b"), find(lookup, "foo", "def"));
-        assertEquals(ImmutableSet.of(), find(lookup, "foo", "ghi"));
-        assertEquals(MANY, find(lookup, "foo", "xyz").size());
-        assertEquals(MANY + 2, find(lookup, "foo", null).size());
+        assertEquals(ImmutableSet.of("a", "b"), find(lookup, "foo", "abc", f));
+        assertEquals(ImmutableSet.of("b"), find(lookup, "foo", "def", f));
+        assertEquals(ImmutableSet.of(), find(lookup, "foo", "ghi", f));
+        assertEquals(MANY, find(lookup, "foo", "xyz", f).size());
+        assertEquals(MANY + 2, find(lookup, "foo", null, f).size());
 
         double cost;
-        cost = lookup.getCost(null, "foo", PropertyValues.newString("xyz"));
+        cost = lookup.getCost(f, "foo", PropertyValues.newString("xyz"));
         assertTrue("cost: " + cost, cost >= MANY);
-        cost = lookup.getCost(null, "foo", null);
+        cost = lookup.getCost(f, "foo", null);
         assertTrue("cost: " + cost, cost >= MANY);
     }
 
@@ -101,14 +101,9 @@ public class Property2IndexTest {
                 : PropertyValues.newString(value)));
     }
 
-    private static Set<String> find(Property2IndexLookup lookup, String name,
-            String value) {
-        return find(lookup, name, value, null);
-    }
-
     @Test
     public void testCustomConfigPropertyLookup() throws Exception {
-        NodeState root = EMPTY_NODE;
+        NodeState root = new InitialContent().initialize(EMPTY_NODE);
 
         // Add index definition
         NodeBuilder builder = root.builder();
@@ -118,7 +113,7 @@ public class Property2IndexTest {
                         Type.NAME)
                 .setProperty("type", "p2")
                 .setProperty("propertyNames", Arrays.asList("foo", "extrafoo"),
-                        Type.STRINGS);
+                        Type.NAMES);
         NodeState before = builder.getNodeState();
 
         // Add some content and process it through the property index hook
@@ -134,26 +129,21 @@ public class Property2IndexTest {
         NodeState after = builder.getNodeState();
 
         // Add an index
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new Property2IndexHook(builder);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
-        NodeState indexed = hook.processCommit(before, after);
+        EditorDiff.process(new Property2IndexHook(builder), before, after);
+        NodeState indexed = builder.getNodeState();
+
+        FilterImpl f = createFilter(indexed, NT_BASE);
 
         // Query the index
         Property2IndexLookup lookup = new Property2IndexLookup(indexed);
-        assertEquals(ImmutableSet.of("a", "b"), find(lookup, "foo", "abc"));
-        assertEquals(ImmutableSet.of("b"), find(lookup, "foo", "def"));
-        assertEquals(ImmutableSet.of(), find(lookup, "foo", "ghi"));
-        assertEquals(MANY, find(lookup, "foo", "xyz").size());
-        assertEquals(ImmutableSet.of("a"), find(lookup, "extrafoo", "pqr"));
+        assertEquals(ImmutableSet.of("a", "b"), find(lookup, "foo", "abc", f));
+        assertEquals(ImmutableSet.of("b"), find(lookup, "foo", "def", f));
+        assertEquals(ImmutableSet.of(), find(lookup, "foo", "ghi", f));
+        assertEquals(MANY, find(lookup, "foo", "xyz", f).size());
+        assertEquals(ImmutableSet.of("a"), find(lookup, "extrafoo", "pqr", f));
 
         try {
-            assertEquals(ImmutableSet.of(), find(lookup, "pqr", "foo"));
+            assertEquals(ImmutableSet.of(), find(lookup, "pqr", "foo", f));
             fail();
         } catch (IllegalArgumentException e) {
             // expected: no index for "pqr"
@@ -167,7 +157,7 @@ public class Property2IndexTest {
      */
     @Test
     public void testCustomConfigNodeType() throws Exception {
-        NodeState root = EMPTY_NODE;
+        NodeState root = new InitialContent().initialize(EMPTY_NODE);
 
         // Add index definitions
         NodeBuilder builder = root.builder();
@@ -177,40 +167,33 @@ public class Property2IndexTest {
                         Type.NAME)
                 .setProperty("type", "p2")
                 .setProperty("propertyNames", Arrays.asList("foo", "extrafoo"),
-                        Type.STRINGS)
+                        Type.NAMES)
                 .setProperty("declaringNodeTypes",
-                        Arrays.asList("nt:unstructured"), Type.STRINGS);
+                        Arrays.asList("nt:unstructured"), Type.NAMES);
         index.child("fooIndexFile")
                 .setProperty("jcr:primaryType", "oak:queryIndexDefinition",
                         Type.NAME)
                 .setProperty("type", "p2")
                 .setProperty("propertyNames", Arrays.asList("foo"),
-                        Type.STRINGS)
+                        Type.NAMES)
                 .setProperty("declaringNodeTypes", Arrays.asList("nt:file"),
-                        Type.STRINGS);
+                        Type.NAMES);
         NodeState before = builder.getNodeState();
 
         // Add some content and process it through the property index hook
         builder = before.builder();
-        builder.child("a").setProperty("jcr:primaryType", "nt:unstructured")
+        builder.child("a")
+                .setProperty("jcr:primaryType", "nt:unstructured", Type.NAME)
                 .setProperty("foo", "abc");
-        builder.child("b").setProperty("jcr:primaryType", "nt:unstructured")
+        builder.child("b")
+                .setProperty("jcr:primaryType", "nt:unstructured", Type.NAME)
                 .setProperty("foo", Arrays.asList("abc", "def"), Type.STRINGS);
         NodeState after = builder.getNodeState();
 
-        // Add an index
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new Property2IndexHook(builder);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
-        NodeState indexed = hook.processCommit(before, after);
+        EditorDiff.process(new Property2IndexHook(builder), before, after);
+        NodeState indexed = builder.getNodeState();
 
-        FilterImpl f = new FilterImpl(null, null);
-        f.setNodeType("nt:unstructured");
+        FilterImpl f = createFilter(indexed, "nt:unstructured");
 
         // Query the index
         Property2IndexLookup lookup = new Property2IndexLookup(indexed);
@@ -226,6 +209,14 @@ public class Property2IndexTest {
         }
     }
 
+    private static FilterImpl createFilter(NodeState root, String nodeTypeName) {
+        NodeState system = root.getChildNode(JCR_SYSTEM);
+        NodeState types = system.getChildNode(JCR_NODE_TYPES);
+        NodeState type = types.getChildNode(nodeTypeName);
+        SelectorImpl selector = new SelectorImpl(type, nodeTypeName);
+        return new FilterImpl(selector, "SELECT * FROM [" + nodeTypeName + "]");
+    }
+
     /**
      * @see <a href="https://issues.apache.org/jira/browse/OAK-666">OAK-666:
      *      Property2Index: node type is used when indexing, but ignored when
@@ -243,38 +234,32 @@ public class Property2IndexTest {
                         Type.NAME)
                 .setProperty("type", "p2")
                 .setProperty("propertyNames", Arrays.asList("foo", "extrafoo"),
-                        Type.STRINGS);
+                        Type.NAMES);
         index.child("fooIndexFile")
                 .setProperty("jcr:primaryType", "oak:queryIndexDefinition",
                         Type.NAME)
                 .setProperty("type", "p2")
                 .setProperty("propertyNames", Arrays.asList("foo"),
-                        Type.STRINGS)
+                        Type.NAMES)
                 .setProperty("declaringNodeTypes", Arrays.asList("nt:file"),
-                        Type.STRINGS);
+                        Type.NAMES);
         NodeState before = builder.getNodeState();
 
         // Add some content and process it through the property index hook
         builder = before.builder();
-        builder.child("a").setProperty("jcr:primaryType", "nt:unstructured")
-                .setProperty("foo", "abc");
-        builder.child("b").setProperty("jcr:primaryType", "nt:unstructured")
-                .setProperty("foo", Arrays.asList("abc", "def"), Type.STRINGS);
+        builder.child("a")
+            .setProperty("jcr:primaryType", "nt:unstructured", Type.NAME)
+            .setProperty("foo", "abc");
+        builder.child("b")
+            .setProperty("jcr:primaryType", "nt:unstructured", Type.NAME)
+            .setProperty("foo", Arrays.asList("abc", "def"), Type.STRINGS);
         NodeState after = builder.getNodeState();
 
         // Add an index
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new Property2IndexHook(builder);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
-        NodeState indexed = hook.processCommit(before, after);
+        EditorDiff.process(new Property2IndexHook(builder), before, after);
+        NodeState indexed = builder.getNodeState();
 
-        FilterImpl f = new FilterImpl(null, null);
-        f.setNodeType("nt:unstructured");
+        FilterImpl f = createFilter(after, "nt:unstructured");
 
         // Query the index
         Property2IndexLookup lookup = new Property2IndexLookup(indexed);
@@ -303,7 +288,7 @@ public class Property2IndexTest {
                 .setProperty("type", "p2")
                 .setProperty("unique", "true")
                 .setProperty("propertyNames", Arrays.asList("foo"),
-                        Type.STRINGS);
+                        Type.NAMES);
 
         NodeState before = builder.getNodeState();
         builder = before.builder();
@@ -312,20 +297,9 @@ public class Property2IndexTest {
                 Type.STRINGS);
         NodeState after = builder.getNodeState();
 
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new Property2IndexHook(builder);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
-        try {
-            hook.processCommit(before, after);
-            fail("Unique constraint should be respected");
-        } catch (CommitFailedException e) {
-            // expected
-        }
+        CommitFailedException expected =
+                EditorDiff.process(new Property2IndexHook(builder), before, after);
+        assertNotNull("Unique constraint should be respected", expected);
     }
 
     @Test
@@ -341,9 +315,9 @@ public class Property2IndexTest {
                 .setProperty("type", "p2")
                 .setProperty("unique", "true")
                 .setProperty("propertyNames", Arrays.asList("foo"),
-                        Type.STRINGS)
+                        Type.NAMES)
                 .setProperty(Property2IndexHook.declaringNodeTypes,
-                        Arrays.asList("typeFoo"), Type.STRINGS);
+                        Arrays.asList("typeFoo"), Type.NAMES);
         NodeState before = builder.getNodeState();
         builder = before.builder();
         builder.child("a").setProperty("jcr:primaryType", "typeFoo", Type.NAME)
@@ -352,15 +326,9 @@ public class Property2IndexTest {
                 .setProperty("foo", "abc");
         NodeState after = builder.getNodeState();
 
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new Property2IndexHook(builder);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
-        hook.processCommit(before, after);
+        CommitFailedException unexpected = EditorDiff.process(
+                new Property2IndexHook(builder), before, after);
+        assertNull(unexpected);
     }
 
     @Test
@@ -376,9 +344,9 @@ public class Property2IndexTest {
                 .setProperty("type", "p2")
                 .setProperty("unique", "true")
                 .setProperty("propertyNames", Arrays.asList("foo"),
-                        Type.STRINGS)
+                        Type.NAMES)
                 .setProperty(Property2IndexHook.declaringNodeTypes,
-                        Arrays.asList("typeFoo"), Type.STRINGS);
+                        Arrays.asList("typeFoo"), Type.NAMES);
         NodeState before = builder.getNodeState();
         builder = before.builder();
         builder.child("a").setProperty("jcr:primaryType", "typeFoo", Type.NAME)
@@ -387,20 +355,9 @@ public class Property2IndexTest {
                 .setProperty("foo", "abc");
         NodeState after = builder.getNodeState();
 
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new Property2IndexHook(builder);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
-        try {
-            hook.processCommit(before, after);
-            fail("Unique constraint should be respected");
-        } catch (CommitFailedException e) {
-            // expected
-        }
+        CommitFailedException expected =
+                EditorDiff.process(new Property2IndexHook(builder), before, after);
+        assertNotNull("Unique constraint should be respected", expected);
     }
 
     @Test
@@ -416,9 +373,9 @@ public class Property2IndexTest {
                 .setProperty("type", "p2")
                 .setProperty("unique", "true")
                 .setProperty("propertyNames", Arrays.asList("foo"),
-                        Type.STRINGS)
+                        Type.NAMES)
                 .setProperty(Property2IndexHook.declaringNodeTypes,
-                        Arrays.asList("typeFoo"), Type.STRINGS);
+                        Arrays.asList("typeFoo"), Type.NAMES);
         builder.child("a").setProperty("jcr:primaryType", "typeFoo", Type.NAME)
                 .setProperty("foo", "abc");
         builder.child("b").setProperty("jcr:primaryType", "typeBar", Type.NAME)
@@ -428,15 +385,9 @@ public class Property2IndexTest {
         builder.removeNode("b");
         NodeState after = builder.getNodeState();
 
-        EditorProvider provider = new EditorProvider() {
-            @Override
-            public Editor getRootEditor(NodeState before, NodeState after,
-                    NodeBuilder builder) {
-                return new Property2IndexHook(builder);
-            }
-        };
-        EditorHook hook = new EditorHook(provider);
-        hook.processCommit(before, after);
+        CommitFailedException unexpected = EditorDiff.process(
+                new Property2IndexHook(builder), before, after);
+        assertNull(unexpected);
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-jcr/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/pom.xml?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-jcr/pom.xml Tue Apr 23 17:06:54 2013
@@ -222,6 +222,7 @@
       org.apache.jackrabbit.test.api.query.SQLJoinTest#testJoinNtBase                                <!-- OAK-474 -->
       org.apache.jackrabbit.test.api.query.SQLJoinTest#testJoinFilterPrimaryType                     <!-- OAK-474 -->
       org.apache.jackrabbit.test.api.query.SQLJoinTest#testJoinSNS                                   <!-- OAK-474 -->
+      org.apache.jackrabbit.test.api.query.qom.DescendantNodeJoinConditionTest#testInnerJoin         <!-- odd side-effect of OAK-325 -->
       org.apache.jackrabbit.test.api.observation.EventTest#testGetUserId
       org.apache.jackrabbit.test.api.observation.NodeMovedTest#testMoveNode
       org.apache.jackrabbit.test.api.observation.NodeMovedTest#testMoveTree

Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java?rev=1471042&r1=1471041&r2=1471042&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java Tue Apr 23 17:06:54 2013
@@ -21,19 +21,10 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import javax.annotation.CheckForNull;
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeIterator;
-import javax.jcr.nodetype.NodeTypeManager;
 
-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.core.ReadOnlyTree;
 import org.apache.jackrabbit.oak.plugins.index.IndexDefinition;
-import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
-import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Cursors;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -61,11 +52,14 @@ import org.apache.lucene.store.Directory
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.jackrabbit.JcrConstants.JCR_MIXINTYPES;
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
 import static org.apache.jackrabbit.oak.commons.PathUtils.elements;
 import static org.apache.jackrabbit.oak.plugins.index.lucene.FieldNames.PATH;
 import static org.apache.jackrabbit.oak.plugins.index.lucene.FieldNames.PATH_SELECTOR;
 import static org.apache.jackrabbit.oak.plugins.index.lucene.TermFactory.newPathTerm;
 import static org.apache.jackrabbit.oak.query.Query.JCR_PATH;
+import static org.apache.lucene.search.BooleanClause.Occur.SHOULD;
 
 /**
  * Provides a QueryIndex that does lookups against a Lucene-based index
@@ -181,11 +175,8 @@ public class LuceneIndex implements Quer
     private static Query getQuery(Filter filter, NodeState root, IndexReader reader) {
         List<Query> qs = new ArrayList<Query>();
 
-        try {
-            addNodeTypeConstraints(qs, filter.getNodeType(), root);
-        } catch (RepositoryException e) {
-            throw new RuntimeException(
-                    "Unable to process node type constraints", e);
+        if (!filter.matchesAllTypes()) {
+            addNodeTypeConstraints(qs, filter);
         }
 
         String path = filter.getPath();
@@ -216,6 +207,8 @@ public class LuceneIndex implements Quer
             }
             qs.add(new TermQuery(newPathTerm(PathUtils.getParentPath(path))));
             break;
+        case NO_RESTRICTION:
+            break;
         }
 
         for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
@@ -314,43 +307,15 @@ public class LuceneIndex implements Quer
         qs.add(bq);
     }
 
-    private static void addNodeTypeConstraints(
-            List<Query> qs, String name, NodeState root)
-            throws RepositoryException {
-        // TODO remove empty name check once OAK-359 is done
-        if (NodeTypeConstants.NT_BASE.equals(name) || "".equals(name)) {
-            return; // shortcut
-        }
-        NodeState system = root.getChildNode(NodeTypeConstants.JCR_SYSTEM);
-        final NodeState types =
-                system.getChildNode(NodeTypeConstants.JCR_NODE_TYPES);
-        if (!types.exists()) {
-            return;
-        }
-
-        NodeTypeManager manager = new ReadOnlyNodeTypeManager() {
-            @Override @CheckForNull
-            protected Tree getTypes() {
-                return new ReadOnlyTree(types);
-            }
-        };
-
+    private static void addNodeTypeConstraints(List<Query> qs, Filter filter) {
         BooleanQuery bq = new BooleanQuery();
-        NodeType type = manager.getNodeType(name);
-        bq.add(createNodeTypeQuery(type), Occur.SHOULD);
-        NodeTypeIterator iterator = type.getSubtypes();
-        while (iterator.hasNext()) {
-            bq.add(createNodeTypeQuery(iterator.nextNodeType()), Occur.SHOULD);
+        for (String type : filter.getPrimaryTypes()) {
+            bq.add(new TermQuery(new Term(JCR_PRIMARYTYPE, type)), SHOULD);
         }
-        qs.add(bq);
-    }
-
-    private static Query createNodeTypeQuery(NodeType type) {
-        String name = NodeTypeConstants.JCR_PRIMARYTYPE;
-        if (type.isMixin()) {
-            name = NodeTypeConstants.JCR_MIXINTYPES;
+        for (String type : filter.getMixinTypes()) {
+            bq.add(new TermQuery(new Term(JCR_MIXINTYPES, type)), SHOULD);
         }
-        return new TermQuery(new Term(name, type.getName()));
+        qs.add(bq);
     }
 
     @Override