You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2007/08/27 14:56:03 UTC

svn commit: r570095 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/query/ main/java/org/apache/jackrabbit/core/query/lucene/ main/java/org/apache/jackrabbit/core/query/sql/ main/java/org/apache/jackrabbit/core/query/xp...

Author: mreutegg
Date: Mon Aug 27 05:56:01 2007
New Revision: 570095

URL: http://svn.apache.org/viewvc?rev=570095&view=rev
Log:
JCR-1066: Exclude system index for queries that restrict the result set to nodetypes not availble in the "jcr:system" subtree

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DefaultQueryNodeFactory.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryNodeFactory.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/AndQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DerefQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/LocationStepQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NodeTypeQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NotQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrderQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PathQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PropertyFunctionQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryParser.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryRootNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryTreeBuilder.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/RelationQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/TextsearchQueryNode.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/JCRSQLQueryBuilder.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/QueryBuilder.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/QueryBuilder.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/PathQueryNodeTest.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/AndQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/AndQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/AndQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/AndQueryNode.java Mon Aug 27 05:56:01 2007
@@ -28,20 +28,8 @@
      *
      * @param parent the parent of <code>this</code> <code>AndQueryNode</code>.
      */
-    public AndQueryNode(QueryNode parent) {
+    protected AndQueryNode(QueryNode parent) {
         super(parent);
-    }
-
-    /**
-     * Creates a new <code>AndQueryNode</code> with a <code>parent</code> query
-     * node and <code>operands</code> for <code>this</code>
-     * <code>AndQueryNode</code>.
-     *
-     * @param parent   the parent of <code>this</code> <code>AndQueryNode</code>.
-     * @param operands the operands for this AND operation.
-     */
-    public AndQueryNode(QueryNode parent, QueryNode[] operands) {
-        super(parent, operands);
     }
 
     /**

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DefaultQueryNodeFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DefaultQueryNodeFactory.java?rev=570095&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DefaultQueryNodeFactory.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DefaultQueryNodeFactory.java Mon Aug 27 05:56:01 2007
@@ -0,0 +1,131 @@
+/*
+ * 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.core.query;
+
+import java.util.List;
+
+import org.apache.jackrabbit.name.QName;
+
+/**
+ * Default implementetation of a {@link QueryNodeFactory}.
+ */
+public class DefaultQueryNodeFactory implements QueryNodeFactory {
+
+    /**
+     * List of valid node type names under /jcr:system
+     */
+    private final List validJcrSystemNodeTypeNames;
+
+    /**
+     * Creates a DefaultQueryNodeFactory with the given node types under
+     * /jcr:system .
+     */
+    public DefaultQueryNodeFactory(List validJcrSystemNodeTypeNames) {
+        super();
+        this.validJcrSystemNodeTypeNames = validJcrSystemNodeTypeNames;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeTypeQueryNode createNodeTypeQueryNode(QueryNode parent,
+                                                     QName nodeType) {
+        return new NodeTypeQueryNode(parent, nodeType);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public AndQueryNode createAndQueryNode(QueryNode parent) {
+        return new AndQueryNode(parent);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public LocationStepQueryNode createLocationStepQueryNode(QueryNode parent) {
+        return new LocationStepQueryNode(parent);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public DerefQueryNode createDerefQueryNode(QueryNode parent,
+                                               QName nameTest,
+                                               boolean descendants) {
+        return new DerefQueryNode(parent, nameTest, descendants);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NotQueryNode createNotQueryNode(QueryNode parent) {
+        return new NotQueryNode(parent);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public OrQueryNode createOrQueryNode(QueryNode parent) {
+        return new OrQueryNode(parent);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public RelationQueryNode createRelationQueryNode(QueryNode parent,
+                                                     int operation) {
+        return new RelationQueryNode(parent, operation);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public PathQueryNode createPathQueryNode(QueryNode parent) {
+        return new PathQueryNode(parent, validJcrSystemNodeTypeNames);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public OrderQueryNode createOrderQueryNode(QueryNode parent) {
+        return new OrderQueryNode(parent);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public PropertyFunctionQueryNode createPropertyFunctionQueryNode(
+            QueryNode parent, String functionName) {
+        return new PropertyFunctionQueryNode(parent, functionName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public QueryRootNode createQueryRootNode() {
+        return new QueryRootNode();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public TextsearchQueryNode createTextsearchQueryNode(QueryNode parent,
+                                                         String query) {
+        return new TextsearchQueryNode(parent, query);
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DefaultQueryNodeFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DerefQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DerefQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DerefQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/DerefQueryNode.java Mon Aug 27 05:56:01 2007
@@ -36,8 +36,10 @@
      * @param descendants if <code>true</code> this location step uses the
      *   descendant-or-self axis; otherwise the child axis.
      */
-    public DerefQueryNode(QueryNode parent, QName nameTest, boolean descendants) {
-        super(parent, nameTest, descendants);
+    protected DerefQueryNode(QueryNode parent, QName nameTest, boolean descendants) {
+        super(parent);
+        setNameTest(nameTest);
+        setIncludeDescendants(descendants);
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/LocationStepQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/LocationStepQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/LocationStepQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/LocationStepQueryNode.java Mon Aug 27 05:56:01 2007
@@ -65,26 +65,11 @@
     private int index = NONE;
 
     /**
-     * Creates a new <code>LocationStepQueryNode</code> with a reference to
-     * its <code>parent</code>.
-     * @param parent the parent of this <code>LocationStepQueryNode</code>.
-     * @param nameTest the name test or <code>null</code> if this step should
-     *   match all names.
-     * @param descendants if <code>true</code> this location step uses the
-     *   descendant-or-self axis; otherwise the child axis.
-     */
-    public LocationStepQueryNode(QueryNode parent, QName nameTest, boolean descendants) {
-        super(parent);
-        this.nameTest = nameTest;
-        this.includeDescendants = descendants;
-    }
-
-    /**
      * Creates a new <code>LocationStepQueryNode</code> that matches only
      * the empty name (the repository root). The created location step
      * uses only the child axis.
      */
-    public LocationStepQueryNode(QueryNode parent) {
+    protected LocationStepQueryNode(QueryNode parent) {
         super(parent);
         this.nameTest = EMPTY_NAME;
         this.includeDescendants = false;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NodeTypeQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NodeTypeQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NodeTypeQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NodeTypeQueryNode.java Mon Aug 27 05:56:01 2007
@@ -29,7 +29,7 @@
      * @param parent   the parent node for this query node.
      * @param nodeType the name of the node type.
      */
-    public NodeTypeQueryNode(QueryNode parent, QName nodeType) {
+    protected NodeTypeQueryNode(QueryNode parent, QName nodeType) {
         // we only use the jcr primary type as a dummy value
         // the property name is actually replaced in the query builder
         // when the runtime query is created to search the index.

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NotQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NotQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NotQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/NotQueryNode.java Mon Aug 27 05:56:01 2007
@@ -26,20 +26,8 @@
      *
      * @param parent the parent node for this query node.
      */
-    public NotQueryNode(QueryNode parent) {
+    protected NotQueryNode(QueryNode parent) {
         super(parent);
-    }
-
-    /**
-     * Creates a new <code>NotQueryNode</code> instance.
-     *
-     * @param parent the parent node for this query node.
-     * @param node   the child query node to invert.
-     */
-    public NotQueryNode(QueryNode parent, QueryNode node) {
-        super(parent, new QueryNode[]{
-            node
-        });
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrQueryNode.java Mon Aug 27 05:56:01 2007
@@ -28,20 +28,8 @@
      *
      * @param parent the parent of <code>this</code> <code>OrQueryNode</code>.
      */
-    public OrQueryNode(QueryNode parent) {
+    protected OrQueryNode(QueryNode parent) {
         super(parent);
-    }
-
-    /**
-     * Creates a new <code>OrQueryNode</code> with a <code>parent</code> query
-     * node and <code>operands</code> for <code>this</code>
-     * <code>OrQueryNode</code>.
-     *
-     * @param parent   the parent of <code>this</code> <code>OrQueryNode</code>.
-     * @param operands the operands for this OR operation.
-     */
-    public OrQueryNode(QueryNode parent, QueryNode[] operands) {
-        super(parent, operands);
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrderQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrderQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrderQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/OrderQueryNode.java Mon Aug 27 05:56:01 2007
@@ -38,7 +38,7 @@
      *
      * @param parent the parent node of this query node.
      */
-    public OrderQueryNode(QueryNode parent) {
+    protected OrderQueryNode(QueryNode parent) {
         super(parent);
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PathQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PathQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PathQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PathQueryNode.java Mon Aug 27 05:56:01 2007
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.core.query;
 
+import java.util.List;
+
 import org.apache.jackrabbit.name.QName;
 
 /**
@@ -29,17 +31,33 @@
     private boolean absolute = false;
 
     /**
+     * List of valid node type names under /jcr:system
+     */
+    private final List validJcrSystemNodeTypeNames;
+
+    /**
      * Empty step node array.
      */
     private static final LocationStepQueryNode[] EMPTY = new LocationStepQueryNode[0];
 
     /**
-     * Creates a relative <code>PathQueryNode</code> with no location steps.
+     * Creates a relative <code>PathQueryNode</code> with no location steps and
+     * the list of node types under /jcr:system.
      *
      * @param parent the parent query node.
      */
-    public PathQueryNode(QueryNode parent) {
+    protected PathQueryNode(QueryNode parent, List validJcrSystemNodeTypeNames) {
         super(parent);
+        this.validJcrSystemNodeTypeNames = validJcrSystemNodeTypeNames;
+    }
+
+    /**
+     * Returns a list of valid node types under /jcr:system. List&lt;QName>.
+     *
+     * @return a list of valid node types under /jcr:system.
+     */
+    public List getValidJcrSystemNodeTypeNames() {
+        return validJcrSystemNodeTypeNames;
     }
 
     /**
@@ -125,10 +143,23 @@
         }
 
         QName firstPathStepName = pathSteps[0].getNameTest();
-        // If the first location step has a null name test we need to include
-        // the system tree ("*")
-        if (firstPathStepName == null)
+        if (firstPathStepName == null) {
+            // If the first operand of the path steps is a node type query
+            // we do not need to include the system index if the node type is
+            // none of the node types that may occur in the system index.
+            QueryNode[] pathStepOperands = pathSteps[0].getOperands();
+            if (pathStepOperands.length > 0) {
+                if (pathStepOperands[0] instanceof NodeTypeQueryNode) {
+                    NodeTypeQueryNode nodeTypeQueryNode = (NodeTypeQueryNode) pathStepOperands[0];
+                    if (!validJcrSystemNodeTypeNames.contains(nodeTypeQueryNode.getValue())) {
+                        return false;
+                    }
+                }
+            }
+            // If the first location step has a null name test we need to include
+            // the system tree ("*")
             return true;
+        }
         
         // Calculate the first workspace relative location step
         LocationStepQueryNode firstWorkspaceRelativeStep = pathSteps[0];

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PropertyFunctionQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PropertyFunctionQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PropertyFunctionQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/PropertyFunctionQueryNode.java Mon Aug 27 05:56:01 2007
@@ -70,7 +70,7 @@
      * @throws IllegalArgumentException if <code>functionName</code> is not a
      *                                  supported function.
      */
-    public PropertyFunctionQueryNode(QueryNode parent, String functionName)
+    protected PropertyFunctionQueryNode(QueryNode parent, String functionName)
             throws IllegalArgumentException {
         super(parent);
         if (!SUPPORTED_FUNCTION_NAMES.contains(functionName)) {

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryNodeFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryNodeFactory.java?rev=570095&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryNodeFactory.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryNodeFactory.java Mon Aug 27 05:56:01 2007
@@ -0,0 +1,137 @@
+/*
+ * 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.core.query;
+
+import org.apache.jackrabbit.name.QName;
+
+/**
+ * A factory for {@link QueryNode}s.
+ */
+public interface QueryNodeFactory {
+
+    /**
+     * Creates a {@link NodeTypeQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @param nodeType the name of the node type.
+     * @return a {@link NodeTypeQueryNode}.
+     */
+    public NodeTypeQueryNode createNodeTypeQueryNode(
+            QueryNode parent, QName nodeType);
+
+    /**
+     * Creates a {@link AndQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @return a {@link AndQueryNode}.
+     */
+    public AndQueryNode createAndQueryNode(
+            QueryNode parent);
+
+    /**
+     * Creates a {@link LocationStepQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @return a {@link LocationStepQueryNode}.
+     */
+    public LocationStepQueryNode createLocationStepQueryNode(
+            QueryNode parent);
+
+    /**
+     * Creates a {@link DerefQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @param nameTest the name test on the referenced target node.
+     * @param descendants if the axis is //
+     * @return a {@link DerefQueryNode}.
+     */
+    public DerefQueryNode createDerefQueryNode(
+            QueryNode parent, QName nameTest, boolean descendants);
+
+    /**
+     * Creates a {@link NotQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @return a {@link NotQueryNode}.
+     */
+    public NotQueryNode createNotQueryNode(
+            QueryNode parent);
+
+    /**
+     * Creates a {@link OrQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @return a {@link OrQueryNode}.
+     */
+    public OrQueryNode createOrQueryNode(
+            QueryNode parent);
+
+    /**
+     * Creates a {@link RelationQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @param operation the operation type.
+     * @return a {@link RelationQueryNode}.
+     */
+    public RelationQueryNode createRelationQueryNode(
+            QueryNode parent, int operation);
+
+    /**
+     * Creates a {@link PathQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @return a {@link PathQueryNode}.
+     */
+    public PathQueryNode createPathQueryNode(
+            QueryNode parent);
+
+    /**
+     * Creates a {@link OrderQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @return a {@link OrderQueryNode}.
+     */
+    public OrderQueryNode createOrderQueryNode(
+            QueryNode parent);
+
+    /**
+     * Creates a {@link PropertyFunctionQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @param functionName the name of the function.
+     * @return a {@link PropertyFunctionQueryNode}.
+     */
+    public PropertyFunctionQueryNode createPropertyFunctionQueryNode(
+            QueryNode parent, String functionName);
+
+    /**
+     * Creates a {@link QueryRootNode} instance.
+     *
+     * @return a {@link QueryRootNode}.
+     */
+    public QueryRootNode createQueryRootNode();
+
+    /**
+     * Creates a {@link TextsearchQueryNode} instance.
+     *
+     * @param parent the parent node.
+     * @param query the textsearch statement.
+     * @return a {@link TextsearchQueryNode}.
+     */
+    public TextsearchQueryNode createTextsearchQueryNode(
+            QueryNode parent, String query);
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryNodeFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryParser.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryParser.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryParser.java Mon Aug 27 05:56:01 2007
@@ -41,17 +41,19 @@
      *
      * @param statement the query statement.
      * @param language  the language of the query statement.
+     * @param factory   the query node factory.
      * @return the root node of the generated query tree.
      * @throws InvalidQueryException if an error occurs while parsing the
      *                               statement.
      */
     public static QueryRootNode parse(String statement,
                                       String language,
-                                      NamespaceResolver resolver)
+                                      NamespaceResolver resolver,
+                                      QueryNodeFactory factory)
             throws InvalidQueryException {
 
         QueryTreeBuilder builder = QueryTreeBuilderRegistry.getQueryTreeBuilder(language);
-        return builder.createQueryTree(statement, resolver);
+        return builder.createQueryTree(statement, resolver, factory);
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryRootNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryRootNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryRootNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryRootNode.java Mon Aug 27 05:56:01 2007
@@ -45,7 +45,7 @@
     /**
      * Creates a new <code>QueryRootNode</code> instance.
      */
-    public QueryRootNode() {
+    protected QueryRootNode() {
         super(null);
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryTreeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryTreeBuilder.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryTreeBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryTreeBuilder.java Mon Aug 27 05:56:01 2007
@@ -26,15 +26,19 @@
 public interface QueryTreeBuilder {
 
     /**
-     * Creates a <code>QueryNode</code> tree from a statement.
+     * Creates a <code>QueryNode</code> tree from a statement using the passed
+     * query node factory.
      *
      * @param statement the statement.
      * @param resolver  the namespace resolver to use.
+     * @param factory   the query node factory to use.
      * @return the <code>QueryNode</code> tree for the statement.
      * @throws javax.jcr.query.InvalidQueryException
      *          if the statement is malformed.
      */
-    QueryRootNode createQueryTree(String statement, NamespaceResolver resolver)
+    QueryRootNode createQueryTree(String statement,
+                                  NamespaceResolver resolver,
+                                  QueryNodeFactory factory)
             throws InvalidQueryException;
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/RelationQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/RelationQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/RelationQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/RelationQueryNode.java Mon Aug 27 05:56:01 2007
@@ -92,77 +92,9 @@
      *
      * @param parent the parent node for this query node.
      */
-    public RelationQueryNode(QueryNode parent, int operation) {
+    protected RelationQueryNode(QueryNode parent, int operation) {
         super(parent);
         this.operation = operation;
-    }
-
-    /**
-     * Creates a new <code>RelationQueryNode</code> with a <code>long</code>
-     * <code>value</code> and an <code>operation</code> type.
-     *
-     * @param parent    the parent node for this query node.
-     * @param relPath   the relative path to a property.
-     * @param value     a property value
-     * @param operation the type of the relation.
-     */
-    public RelationQueryNode(QueryNode parent, Path relPath, long value, int operation) {
-        super(parent);
-        this.relPath = relPath;
-        this.valueLong = value;
-        this.operation = operation;
-        this.type = TYPE_LONG;
-    }
-
-    /**
-     * Creates a new <code>RelationQueryNode</code> with a <code>double</code>
-     * <code>value</code> and an <code>operation</code> type.
-     *
-     * @param parent    the parent node for this query node.
-     * @param relPath   the relative path to a property.
-     * @param value     a property value
-     * @param operation the type of the relation.
-     */
-    public RelationQueryNode(QueryNode parent, Path relPath, double value, int operation) {
-        super(parent);
-        this.relPath = relPath;
-        this.valueDouble = value;
-        this.operation = operation;
-        this.type = TYPE_DOUBLE;
-    }
-
-    /**
-     * Creates a new <code>RelationQueryNode</code> with a <code>Date</code>
-     * <code>value</code> and an <code>operation</code> type.
-     *
-     * @param parent    the parent node for this query node.
-     * @param relPath   the relative path to a property.
-     * @param value     a property value
-     * @param operation the type of the relation.
-     */
-    public RelationQueryNode(QueryNode parent, Path relPath, Date value, int operation) {
-        super(parent);
-        this.relPath = relPath;
-        this.valueDate = value;
-        this.operation = operation;
-        this.type = TYPE_DATE;
-    }
-
-    /**
-     * Creates a new <code>RelationQueryNode</code> with a <code>String</code>
-     * <code>value</code> and an <code>operation</code> type.
-     *
-     * @param parent    the parent node for this query node.
-     * @param relPath   the relative path to a property.
-     * @param value     a property value
-     * @param operation the type of the relation.
-     */
-    public RelationQueryNode(QueryNode parent, Path relPath, String value, int operation) {
-        super(parent);
-        this.relPath = relPath;
-        this.valueString = value;
-        this.operation = operation;
-        this.type = TYPE_STRING;
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/TextsearchQueryNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/TextsearchQueryNode.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/TextsearchQueryNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/TextsearchQueryNode.java Mon Aug 27 05:56:01 2007
@@ -52,27 +52,11 @@
      * @param parent the parent node of this query node.
      * @param query  the textsearch statement.
      */
-    public TextsearchQueryNode(QueryNode parent, String query) {
-        this(parent, query, null, false);
-    }
-
-    /**
-     * Creates a new <code>TextsearchQueryNode</code> with a <code>parent</code>
-     * and a textsearch <code>query</code> statement. The scope of the query is
-     * the property or node referenced by <code>relPath</code>.
-     *
-     * @param parent     the parent node of this query node.
-     * @param query      the textsearch statement.
-     * @param relPath    scope of the fulltext search. If <code>null</code> the
-     *                   context node is searched.
-     * @param isProperty if <code>relPath</code> references a property or a
-     *                   node.
-     */
-    public TextsearchQueryNode(QueryNode parent, String query, Path relPath, boolean isProperty) {
+    protected TextsearchQueryNode(QueryNode parent, String query) {
         super(parent);
         this.query = query;
-        this.relPath = relPath;
-        this.propertyRef = isProperty;
+        this.relPath = null;
+        this.propertyRef = false;
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java Mon Aug 27 05:56:01 2007
@@ -30,6 +30,7 @@
 import org.apache.jackrabbit.core.query.QueryParser;
 import org.apache.jackrabbit.core.query.QueryRootNode;
 import org.apache.jackrabbit.core.query.AndQueryNode;
+import org.apache.jackrabbit.core.query.QueryNodeFactory;
 import org.apache.jackrabbit.name.QName;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -56,14 +57,7 @@
     /**
      * Represents a query that selects all nodes. E.g. in XPath: //*
      */
-    protected static final QueryRootNode ALL_NODES = new QueryRootNode();
-
-    static {
-        PathQueryNode pathNode = new PathQueryNode(ALL_NODES);
-        pathNode.addPathStep(new LocationStepQueryNode(pathNode, null, true));
-        pathNode.setAbsolute(true);
-        ALL_NODES.setLocationNode(pathNode);
-    }
+    protected final QueryRootNode allNodesQueryNode;
 
     /**
      * The root node of the query tree
@@ -105,6 +99,7 @@
      * @param propReg   the property type registry.
      * @param statement the query statement.
      * @param language  the syntax of the query statement.
+     * @param factory   the query node factory.
      * @throws InvalidQueryException if the query statement is invalid according
      *                               to the specified <code>language</code>.
      */
@@ -113,14 +108,26 @@
                      SearchIndex index,
                      PropertyTypeRegistry propReg,
                      String statement,
-                     String language) throws InvalidQueryException {
+                     String language,
+                     QueryNodeFactory factory) throws InvalidQueryException {
         this.session = session;
         this.itemMgr = itemMgr;
         this.index = index;
         this.propReg = propReg;
         // parse query according to language
-        // build query tree
-        this.root = QueryParser.parse(statement, language, session.getNamespaceResolver());
+        // build query tree using the passed factory
+        this.root = QueryParser.parse(statement, language,
+                session.getNamespaceResolver(), factory);
+
+        allNodesQueryNode = factory.createQueryRootNode();
+        PathQueryNode pathNode = factory.createPathQueryNode(allNodesQueryNode);
+        LocationStepQueryNode lsNode = factory.createLocationStepQueryNode(pathNode);
+        lsNode.setNameTest(null);
+        lsNode.setIncludeDescendants(true);
+        pathNode.addPathStep(lsNode);
+        pathNode.setAbsolute(true);
+        allNodesQueryNode.setLocationNode(pathNode);
+        
     }
 
     /**
@@ -137,7 +144,7 @@
         }
 
         // check for special query
-        if (ALL_NODES.equals(root)) {
+        if (allNodesQueryNode.equals(root)) {
             return new WorkspaceTraversalResult(session,
                     new QName[] { QName.JCR_PRIMARYTYPE, QName.JCR_PATH, QName.JCR_SCORE },
                     session.getNamespaceResolver());

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java Mon Aug 27 05:56:01 2007
@@ -21,6 +21,7 @@
 import org.apache.jackrabbit.core.NodeId;
 import org.apache.jackrabbit.core.NodeIdIterator;
 import org.apache.jackrabbit.core.query.AbstractQueryHandler;
+import org.apache.jackrabbit.core.query.DefaultQueryNodeFactory;
 import org.apache.jackrabbit.core.query.ExecutableQuery;
 import org.apache.jackrabbit.core.query.QueryHandlerContext;
 import org.apache.jackrabbit.core.query.QueryHandler;
@@ -59,6 +60,7 @@
 import javax.xml.parsers.ParserConfigurationException;
 import java.io.IOException;
 import java.io.File;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ArrayList;
@@ -74,6 +76,27 @@
  */
 public class SearchIndex extends AbstractQueryHandler {
 
+    public static final List VALID_SYSTEM_INDEX_NODE_TYPE_NAMES
+        = Collections.unmodifiableList(Arrays.asList(new QName[]{
+            QName.NT_CHILDNODEDEFINITION,
+            QName.NT_FROZENNODE,
+            QName.NT_NODETYPE,
+            QName.NT_PROPERTYDEFINITION,
+            QName.NT_VERSION,
+            QName.NT_VERSIONEDCHILD,
+            QName.NT_VERSIONHISTORY,
+            QName.NT_VERSIONLABELS,
+            QName.REP_NODETYPES,
+            QName.REP_SYSTEM,
+            QName.REP_VERSIONSTORAGE,
+            // Supertypes
+            QName.NT_BASE,
+            QName.MIX_REFERENCEABLE
+        }));
+
+    private static final DefaultQueryNodeFactory DEFAULT_QUERY_NODE_FACTORY = new DefaultQueryNodeFactory(
+            VALID_SYSTEM_INDEX_NODE_TYPE_NAMES);
+
     /** The logger instance for this class */
     private static final Logger log = LoggerFactory.getLogger(SearchIndex.class);
 
@@ -492,9 +515,17 @@
                                              String language)
             throws InvalidQueryException {
         QueryImpl query = new QueryImpl(session, itemMgr, this,
-                getContext().getPropertyTypeRegistry(), statement, language);
+                getContext().getPropertyTypeRegistry(), statement, language, getQueryNodeFactory());
         query.setRespectDocumentOrder(documentOrder);
         return query;
+    }
+
+    /**
+     * This method returns the QueryNodeFactory used to parse Queries. This method
+     * may be overridden to provide a customized QueryNodeFactory
+     */
+    protected DefaultQueryNodeFactory getQueryNodeFactory() {
+        return DEFAULT_QUERY_NODE_FACTORY;
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/JCRSQLQueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/JCRSQLQueryBuilder.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/JCRSQLQueryBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/JCRSQLQueryBuilder.java Mon Aug 27 05:56:01 2007
@@ -30,6 +30,7 @@
 import org.apache.jackrabbit.core.query.RelationQueryNode;
 import org.apache.jackrabbit.core.query.TextsearchQueryNode;
 import org.apache.jackrabbit.core.query.PropertyFunctionQueryNode;
+import org.apache.jackrabbit.core.query.QueryNodeFactory;
 import org.apache.jackrabbit.name.NameException;
 import org.apache.jackrabbit.name.NamespaceResolver;
 import org.apache.jackrabbit.name.QName;
@@ -74,7 +75,6 @@
      */
     private static Map parsers = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
 
-
     /**
      * The root node of the sql query syntax tree
      */
@@ -93,7 +93,7 @@
     /**
      * Query node to gather the constraints defined in the WHERE clause
      */
-    private final AndQueryNode constraintNode = new AndQueryNode(null);
+    private final AndQueryNode constraintNode;
 
     /**
      * The QName of the node type in the from clause.
@@ -106,26 +106,39 @@
     private final List pathConstraints = new ArrayList();
 
     /**
+     * The query node factory.
+     */
+    private final QueryNodeFactory factory;
+
+    /**
      * Creates a new <code>JCRSQLQueryBuilder</code>.
      *
      * @param statement the root node of the SQL syntax tree.
      * @param resolver  a namespace resolver to use for names in the
      *                  <code>statement</code>.
+     * @param factory   the query node factory.
      */
-    private JCRSQLQueryBuilder(ASTQuery statement, NamespaceResolver resolver) {
+    private JCRSQLQueryBuilder(ASTQuery statement,
+                               NamespaceResolver resolver,
+                               QueryNodeFactory factory) {
         this.stmt = statement;
         this.resolver = resolver;
+        this.factory = factory;
+        this.constraintNode =  factory.createAndQueryNode(null);
     }
 
     /**
-     * Creates a <code>QueryNode</code> tree from a SQL <code>statement</code>.
+     * Creates a <code>QueryNode</code> tree from a SQL <code>statement</code>
+     * using the passed query node <code>factory</code>.
      *
      * @param statement the SQL statement.
      * @param resolver  the namespace resolver to use.
      * @return the <code>QueryNode</code> tree.
      * @throws InvalidQueryException if <code>statement</code> is malformed.
      */
-    public static QueryRootNode createQuery(String statement, NamespaceResolver resolver)
+    public static QueryRootNode createQuery(String statement,
+                                            NamespaceResolver resolver,
+                                            QueryNodeFactory factory)
             throws InvalidQueryException {
         try {
             // get parser
@@ -143,7 +156,7 @@
             // guard against concurrent use within same session
             synchronized (parser) {
                 parser.ReInit(new StringReader(statement));
-                builder = new JCRSQLQueryBuilder(parser.Query(), resolver);
+                builder = new JCRSQLQueryBuilder(parser.Query(), resolver, factory);
             }
             return builder.getRootNode();
         } catch (ParseException e) {
@@ -191,8 +204,8 @@
     }
 
     public Object visit(ASTQuery node, Object data) {
-        root = new QueryRootNode();
-        root.setLocationNode(new PathQueryNode(root));
+        root = factory.createQueryRootNode();
+        root.setLocationNode(factory.createPathQueryNode(root));
 
         // pass to select, from, where, ...
         node.childrenAccept(this, root);
@@ -201,7 +214,10 @@
         PathQueryNode pathNode = root.getLocationNode();
         pathNode.setAbsolute(true);
         if (pathConstraints.size() == 0) {
-            pathNode.addPathStep(new LocationStepQueryNode(pathNode, null, true));
+            LocationStepQueryNode step = factory.createLocationStepQueryNode(pathNode);
+            step.setNameTest(null);
+            step.setIncludeDescendants(true);
+            pathNode.addPathStep(step);
         } else {
             try {
                 while (pathConstraints.size() > 1) {
@@ -231,7 +247,9 @@
             MergingPathQueryNode path = (MergingPathQueryNode) pathConstraints.get(0);
             LocationStepQueryNode[] steps = path.getPathSteps();
             for (int i = 0; i < steps.length; i++) {
-                LocationStepQueryNode step = new LocationStepQueryNode(pathNode, steps[i].getNameTest(), steps[i].getIncludeDescendants());
+                LocationStepQueryNode step = factory.createLocationStepQueryNode(pathNode);
+                step.setNameTest(steps[i].getNameTest());
+                step.setIncludeDescendants(steps[i].getIncludeDescendants());
                 step.setIndex(steps[i].getIndex());
                 pathNode.addPathStep(step);
             }
@@ -247,7 +265,7 @@
             // add node type constraint
             LocationStepQueryNode[] steps = pathNode.getPathSteps();
             NodeTypeQueryNode nodeType
-                    = new NodeTypeQueryNode(steps[steps.length - 1], nodeTypeName);
+                    = factory.createNodeTypeQueryNode(steps[steps.length - 1], nodeTypeName);
             steps[steps.length - 1].addPredicate(nodeType);
         }
 
@@ -351,7 +369,7 @@
             }
 
             if (type == QueryConstants.OPERATION_BETWEEN) {
-                AndQueryNode between = new AndQueryNode(parent);
+                AndQueryNode between = factory.createAndQueryNode(parent);
                 RelationQueryNode rel = createRelationQueryNode(between,
                         identifier, QueryConstants.OPERATION_GE_GENERAL, (ASTLiteral) node.children[1]);
                 node.childrenAccept(this, rel);
@@ -389,7 +407,7 @@
                         identifier, type, pattern);
                 node.childrenAccept(this, predicateNode);
             } else if (type == QueryConstants.OPERATION_IN) {
-                OrQueryNode in = new OrQueryNode(parent);
+                OrQueryNode in = factory.createOrQueryNode(parent);
                 for (int i = 1; i < node.children.length; i++) {
                     RelationQueryNode rel = createRelationQueryNode(in,
                             identifier, QueryConstants.OPERATION_EQ_VALUE, (ASTLiteral) node.children[i]);
@@ -424,7 +442,7 @@
 
     public Object visit(ASTOrExpression node, Object data) {
         NAryQueryNode parent = (NAryQueryNode) data;
-        OrQueryNode orQuery = new OrQueryNode(parent);
+        OrQueryNode orQuery = factory.createOrQueryNode(parent);
         // pass to operands
         node.childrenAccept(this, orQuery);
 
@@ -436,7 +454,7 @@
 
     public Object visit(ASTAndExpression node, Object data) {
         NAryQueryNode parent = (NAryQueryNode) data;
-        AndQueryNode andQuery = new AndQueryNode(parent);
+        AndQueryNode andQuery = factory.createAndQueryNode(parent);
         // pass to operands
         node.childrenAccept(this, andQuery);
 
@@ -446,7 +464,7 @@
 
     public Object visit(ASTNotExpression node, Object data) {
         NAryQueryNode parent = (NAryQueryNode) data;
-        NotQueryNode notQuery = new NotQueryNode(parent);
+        NotQueryNode notQuery = factory.createNotQueryNode(parent);
         // pass to operand
         node.childrenAccept(this, notQuery);
 
@@ -474,7 +492,7 @@
     public Object visit(ASTOrderByClause node, Object data) {
         QueryRootNode root = (QueryRootNode) data;
 
-        OrderQueryNode order = new OrderQueryNode(root);
+        OrderQueryNode order = factory.createOrderQueryNode(root);
         root.setOrderNode(order);
         node.childrenAccept(this, order);
         return root;
@@ -521,7 +539,10 @@
                 builder.addLast(node.getPropertyName());
                 relPath = builder.getPath();
             }
-            parent.addOperand(new TextsearchQueryNode(parent, node.getQuery(), relPath, true));
+            TextsearchQueryNode tsNode = factory.createTextsearchQueryNode(parent, node.getQuery());
+            tsNode.setRelativePath(relPath);
+            tsNode.setReferencesProperty(true);
+            parent.addOperand(tsNode);
         } catch (MalformedPathException e) {
             // path is always valid
         }
@@ -534,7 +555,7 @@
             String msg = "LOWER() function is only supported for String literal";
             throw new IllegalArgumentException(msg);
         }
-        parent.addOperand(new PropertyFunctionQueryNode(parent, PropertyFunctionQueryNode.LOWER_CASE));
+        parent.addOperand(factory.createPropertyFunctionQueryNode(parent, PropertyFunctionQueryNode.LOWER_CASE));
         return parent;
     }
 
@@ -544,7 +565,7 @@
             String msg = "UPPER() function is only supported for String literal";
             throw new IllegalArgumentException(msg);
         }
-        parent.addOperand(new PropertyFunctionQueryNode(parent, PropertyFunctionQueryNode.UPPER_CASE));
+        parent.addOperand(factory.createPropertyFunctionQueryNode(parent, PropertyFunctionQueryNode.UPPER_CASE));
         return parent;
     }
 
@@ -585,18 +606,28 @@
             if (literal.getType() == QueryConstants.TYPE_DATE) {
                 SimpleDateFormat format = new SimpleDateFormat(DATE_PATTERN);
                 Date date = format.parse(stringValue);
-                node = new RelationQueryNode(parent, relPath, date, operationType);
+                node = factory.createRelationQueryNode(parent, operationType);
+                node.setRelativePath(relPath);
+                node.setDateValue(date);
             } else if (literal.getType() == QueryConstants.TYPE_DOUBLE) {
                 double d = Double.parseDouble(stringValue);
-                node = new RelationQueryNode(parent, relPath, d, operationType);
+                node = factory.createRelationQueryNode(parent, operationType);
+                node.setRelativePath(relPath);
+                node.setDoubleValue(d);
             } else if (literal.getType() == QueryConstants.TYPE_LONG) {
                 long l = Long.parseLong(stringValue);
-                node = new RelationQueryNode(parent, relPath, l, operationType);
+                node = factory.createRelationQueryNode(parent, operationType);
+                node.setRelativePath(relPath);
+                node.setLongValue(l);
             } else if (literal.getType() == QueryConstants.TYPE_STRING) {
-                node = new RelationQueryNode(parent, relPath, stringValue, operationType);
+                node = factory.createRelationQueryNode(parent, operationType);
+                node.setRelativePath(relPath);
+                node.setStringValue(stringValue);
             } else if (literal.getType() == QueryConstants.TYPE_TIMESTAMP) {
                 Calendar c = ISO8601.parse(stringValue);
-                node = new RelationQueryNode(parent, relPath, c.getTime(), operationType);
+                node = factory.createRelationQueryNode(parent, operationType);
+                node.setRelativePath(relPath);
+                node.setDateValue(c.getTime());
             }
         } catch (java.text.ParseException e) {
             throw new IllegalArgumentException(e.toString());
@@ -620,11 +651,12 @@
      * @param operation the type of the parent node
      */
     private void createPathQuery(String path, int operation) {
-        MergingPathQueryNode pathNode = new MergingPathQueryNode(operation);
+        MergingPathQueryNode pathNode = new MergingPathQueryNode(operation,
+                factory.createPathQueryNode(null).getValidJcrSystemNodeTypeNames());
         pathNode.setAbsolute(true);
 
         if (path.equals("/")) {
-            pathNode.addPathStep(new LocationStepQueryNode(pathNode));
+            pathNode.addPathStep(factory.createLocationStepQueryNode(pathNode));
             pathConstraints.add(pathNode);
             return;
         }
@@ -635,13 +667,13 @@
             if (names[i].length() == 0) {
                 if (i == 0) {
                     // root
-                    pathNode.addPathStep(new LocationStepQueryNode(pathNode));
+                    pathNode.addPathStep(factory.createLocationStepQueryNode(pathNode));
                 } else {
                     // descendant '//' -> invalid path
                     // todo throw or ignore?
                     // we currently do not throw and add location step for an
                     // empty name (which is basically the root node)
-                    pathNode.addPathStep(new LocationStepQueryNode(pathNode));
+                    pathNode.addPathStep(factory.createLocationStepQueryNode(pathNode));
                 }
             } else {
                 int idx = names[i].indexOf('[');
@@ -686,7 +718,9 @@
                 }
                 // if name test is % this means also search descendants
                 boolean descendant = name == null;
-                LocationStepQueryNode step = new LocationStepQueryNode(pathNode, qName, descendant);
+                LocationStepQueryNode step = factory.createLocationStepQueryNode(pathNode);
+                step.setNameTest(qName);
+                step.setIncludeDescendants(descendant);
                 if (index > 0) {
                     step.setIndex(index);
                 }
@@ -779,9 +813,11 @@
          * {@link org.apache.jackrabbit.core.query.QueryNode#TYPE_NOT}.
          *
          * @param operation the operation type of the parent node.
+         * @param validJcrSystemNodeTypeNames names of valid node types under
+         *        /jcr:system.
          */
-        MergingPathQueryNode(int operation) {
-            super(null);
+        MergingPathQueryNode(int operation, List validJcrSystemNodeTypeNames) {
+            super(null, validJcrSystemNodeTypeNames);
             if (operation != QueryNode.TYPE_OR && operation != QueryNode.TYPE_AND && operation != QueryNode.TYPE_NOT) {
                 throw new IllegalArgumentException("operation");
             }
@@ -883,7 +919,8 @@
          */
         private MergingPathQueryNode[] doOrMerge(MergingPathQueryNode[] nodes) {
             // compact this
-            MergingPathQueryNode compacted = new MergingPathQueryNode(QueryNode.TYPE_OR);
+            MergingPathQueryNode compacted = new MergingPathQueryNode(
+                    QueryNode.TYPE_OR, getValidJcrSystemNodeTypeNames());
             for (Iterator it = operands.iterator(); it.hasNext();) {
                 LocationStepQueryNode step = (LocationStepQueryNode) it.next();
                 if (step.getIncludeDescendants() && step.getNameTest() == null) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/QueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/QueryBuilder.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/QueryBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/sql/QueryBuilder.java Mon Aug 27 05:56:01 2007
@@ -18,6 +18,7 @@
 
 import org.apache.jackrabbit.core.query.QueryTreeBuilder;
 import org.apache.jackrabbit.core.query.QueryRootNode;
+import org.apache.jackrabbit.core.query.QueryNodeFactory;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
 import javax.jcr.query.InvalidQueryException;
@@ -32,9 +33,10 @@
      * @inheritDoc
      */
     public QueryRootNode createQueryTree(String statement,
-                                         NamespaceResolver resolver)
+                                         NamespaceResolver resolver,
+                                         QueryNodeFactory factory)
             throws InvalidQueryException {
-        return JCRSQLQueryBuilder.createQuery(statement, resolver);
+        return JCRSQLQueryBuilder.createQuery(statement, resolver, factory);
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/QueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/QueryBuilder.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/QueryBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/QueryBuilder.java Mon Aug 27 05:56:01 2007
@@ -18,6 +18,7 @@
 
 import org.apache.jackrabbit.core.query.QueryTreeBuilder;
 import org.apache.jackrabbit.core.query.QueryRootNode;
+import org.apache.jackrabbit.core.query.QueryNodeFactory;
 import org.apache.jackrabbit.name.NamespaceResolver;
 
 import javax.jcr.query.InvalidQueryException;
@@ -32,9 +33,10 @@
      * @inheritDoc
      */
     public QueryRootNode createQueryTree(String statement,
-                                         NamespaceResolver resolver)
+                                         NamespaceResolver resolver,
+                                         QueryNodeFactory factory)
             throws InvalidQueryException {
-        return XPathQueryBuilder.createQuery(statement, resolver);
+        return XPathQueryBuilder.createQuery(statement, resolver, factory);
     }
 
     /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/xpath/XPathQueryBuilder.java Mon Aug 27 05:56:01 2007
@@ -16,13 +16,11 @@
  */
 package org.apache.jackrabbit.core.query.xpath;
 
-import org.apache.jackrabbit.core.query.AndQueryNode;
 import org.apache.jackrabbit.core.query.DerefQueryNode;
 import org.apache.jackrabbit.core.query.LocationStepQueryNode;
 import org.apache.jackrabbit.core.query.NAryQueryNode;
 import org.apache.jackrabbit.core.query.NodeTypeQueryNode;
 import org.apache.jackrabbit.core.query.NotQueryNode;
-import org.apache.jackrabbit.core.query.OrQueryNode;
 import org.apache.jackrabbit.core.query.OrderQueryNode;
 import org.apache.jackrabbit.core.query.PathQueryNode;
 import org.apache.jackrabbit.core.query.QueryConstants;
@@ -32,6 +30,7 @@
 import org.apache.jackrabbit.core.query.TextsearchQueryNode;
 import org.apache.jackrabbit.core.query.PropertyFunctionQueryNode;
 import org.apache.jackrabbit.core.query.DefaultQueryNodeVisitor;
+import org.apache.jackrabbit.core.query.QueryNodeFactory;
 import org.apache.jackrabbit.name.NameException;
 import org.apache.jackrabbit.name.NamespaceResolver;
 import org.apache.jackrabbit.name.NoPrefixDeclaredException;
@@ -223,7 +222,7 @@
     /**
      * The root <code>QueryNode</code>
      */
-    private final QueryRootNode root = new QueryRootNode();
+    private final QueryRootNode root;
 
     /**
      * The {@link NamespaceResolver} in use
@@ -241,15 +240,25 @@
     private Path.PathBuilder tmpRelPath;
 
     /**
+     * The query node factory.
+     */
+    private final QueryNodeFactory factory;
+
+    /**
      * Creates a new <code>XPathQueryBuilder</code> instance.
      *
      * @param statement the XPath statement.
      * @param resolver  the namespace resolver to use.
+     * @param factory   the query node factory.
      * @throws InvalidQueryException if the XPath statement is malformed.
      */
-    private XPathQueryBuilder(String statement, NamespaceResolver resolver)
+    private XPathQueryBuilder(String statement,
+                              NamespaceResolver resolver,
+                              QueryNodeFactory factory)
             throws InvalidQueryException {
         this.resolver = resolver;
+        this.factory = factory;
+        this.root = factory.createQueryRootNode();
         try {
             // create an XQuery statement because we're actually using an
             // XQuery parser.
@@ -291,17 +300,20 @@
     }
 
     /**
-     * Creates a <code>QueryNode</code> tree from a XPath statement.
+     * Creates a <code>QueryNode</code> tree from a XPath statement using the
+     * passed query node <code>factory</code>.
      *
      * @param statement the XPath statement.
      * @param resolver  the namespace resolver to use.
+     * @param factory   the query node factory.
      * @return the <code>QueryNode</code> tree for the XPath statement.
      * @throws InvalidQueryException if the XPath statement is malformed.
      */
     public static QueryRootNode createQuery(String statement,
-                                            NamespaceResolver resolver)
+                                            NamespaceResolver resolver,
+                                            QueryNodeFactory factory)
             throws InvalidQueryException {
-        return new XPathQueryBuilder(statement, resolver).getRootNode();
+        return new XPathQueryBuilder(statement, resolver, factory).getRootNode();
     }
 
     /**
@@ -365,7 +377,7 @@
                     } else if (queryNode.getType() == QueryNode.TYPE_NOT) {
                         // is null expression
                         RelationQueryNode isNull
-                                = new RelationQueryNode(queryNode,
+                                = factory.createRelationQueryNode(queryNode,
                                         RelationQueryNode.OPERATION_NULL);
                         applyRelativePath(isNull);
                         node.childrenAccept(this, isNull);
@@ -376,7 +388,7 @@
                     } else {
                         // not null expression
                         RelationQueryNode notNull =
-                                new RelationQueryNode(queryNode,
+                                factory.createRelationQueryNode(queryNode,
                                         RelationQueryNode.OPERATION_NOT_NULL);
                         applyRelativePath(notNull);
                         node.childrenAccept(this, notNull);
@@ -390,7 +402,7 @@
                         node.childrenAccept(this, queryNode);
                     } else {
                         // step within a predicate
-                        RelationQueryNode tmp = new RelationQueryNode(
+                        RelationQueryNode tmp = factory.createRelationQueryNode(
                                 null, RelationQueryNode.OPERATION_NOT_NULL);
                         node.childrenAccept(this, tmp);
                         if (tmpRelPath == null) {
@@ -434,7 +446,7 @@
                     String ntName = ((SimpleNode) node.jjtGetChild(0)).getValue();
                     try {
                         QName nt = NameFormat.parse(ntName, resolver);
-                        NodeTypeQueryNode nodeType = new NodeTypeQueryNode(loc, nt);
+                        NodeTypeQueryNode nodeType = factory.createNodeTypeQueryNode(loc, nt);
                         loc.addPredicate(nodeType);
                     } catch (NameException e) {
                         exceptions.add(new InvalidQueryException("Not a valid name: " + ntName));
@@ -443,14 +455,14 @@
                 break;
             case JJTOREXPR:
                 NAryQueryNode parent = (NAryQueryNode) queryNode;
-                QueryNode orQueryNode = new OrQueryNode(parent);
+                QueryNode orQueryNode = factory.createOrQueryNode(parent);
                 parent.addOperand(orQueryNode);
                 // traverse
                 node.childrenAccept(this, orQueryNode);
                 break;
             case JJTANDEXPR:
                 parent = (NAryQueryNode) queryNode;
-                QueryNode andQueryNode = new AndQueryNode(parent);
+                QueryNode andQueryNode = factory.createAndQueryNode(parent);
                 parent.addOperand(andQueryNode);
                 // traverse
                 node.childrenAccept(this, andQueryNode);
@@ -486,7 +498,7 @@
                 queryNode = createFunction(node, queryNode);
                 break;
             case JJTORDERBYCLAUSE:
-                root.setOrderNode(new OrderQueryNode(root));
+                root.setOrderNode(factory.createOrderQueryNode(root));
                 queryNode = root.getOrderNode();
                 node.childrenAccept(this, queryNode);
                 break;
@@ -561,7 +573,9 @@
         for (int i = 0; i < p.jjtGetNumChildren(); i++) {
             SimpleNode c = (SimpleNode) p.jjtGetChild(i);
             if (c == node) {
-                queryNode = new LocationStepQueryNode(parent, null, descendant);
+                queryNode = factory.createLocationStepQueryNode(parent);
+                queryNode.setNameTest(null);
+                queryNode.setIncludeDescendants(descendant);
                 parent.addOperand(queryNode);
                 break;
             }
@@ -670,7 +684,7 @@
             exceptions.add(new InvalidQueryException("Unsupported ComparisonExpr type:" + node.getValue()));
         }
 
-        final RelationQueryNode rqn = new RelationQueryNode(queryNode, type);
+        final RelationQueryNode rqn = factory.createRelationQueryNode(queryNode, type);
 
         // traverse
         node.childrenAccept(this, rqn);
@@ -699,7 +713,7 @@
      * @return the path qurey node
      */
     private PathQueryNode createPathQueryNode(SimpleNode node) {
-        root.setLocationNode(new PathQueryNode(root));
+        root.setLocationNode(factory.createPathQueryNode(root));
         node.childrenAccept(this, root.getLocationNode());
         return root.getLocationNode();
     }
@@ -746,7 +760,7 @@
             if (NameFormat.format(FN_NOT, resolver).equals(fName)
                     || NameFormat.format(FN_NOT_10, resolver).equals(fName)) {
                 if (queryNode instanceof NAryQueryNode) {
-                    QueryNode not = new NotQueryNode(queryNode);
+                    QueryNode not = factory.createNotQueryNode(queryNode);
                     ((NAryQueryNode) queryNode).addOperand(not);
                     // @todo is this needed?
                     queryNode = not;
@@ -791,7 +805,7 @@
                     if (queryNode instanceof NAryQueryNode) {
                         SimpleNode literal = (SimpleNode) node.jjtGetChild(2).jjtGetChild(0);
                         if (literal.getId() == JJTSTRINGLITERAL) {
-                            TextsearchQueryNode contains = new TextsearchQueryNode(
+                            TextsearchQueryNode contains = factory.createTextsearchQueryNode(
                                     queryNode, unescapeQuotes(literal.getValue()));
                             // assign property name
                             SimpleNode path = (SimpleNode) node.jjtGetChild(1);
@@ -809,7 +823,8 @@
                 // check number of arguments
                 if (node.jjtGetNumChildren() == 3) {
                     if (queryNode instanceof NAryQueryNode) {
-                        RelationQueryNode like = new RelationQueryNode(queryNode, RelationQueryNode.OPERATION_LIKE);
+                        RelationQueryNode like = factory.createRelationQueryNode(
+                                queryNode, RelationQueryNode.OPERATION_LIKE);
                         ((NAryQueryNode) queryNode).addOperand(like);
 
                         // assign property name
@@ -889,7 +904,7 @@
                     }
                     if (queryNode.getType() == QueryNode.TYPE_PATH) {
                         PathQueryNode pathNode = (PathQueryNode) queryNode;
-                        DerefQueryNode derefNode = new DerefQueryNode(pathNode, null, false);
+                        DerefQueryNode derefNode = factory.createDerefQueryNode(pathNode, null, false);
 
                         // assign property name
                         node.jjtGetChild(1).jjtAccept(this, derefNode);
@@ -944,7 +959,8 @@
                 if (node.jjtGetNumChildren() == 2) {
                     if (queryNode.getType() == QueryNode.TYPE_RELATION) {
                         RelationQueryNode relNode = (RelationQueryNode) queryNode;
-                        relNode.addOperand(new PropertyFunctionQueryNode(relNode, PropertyFunctionQueryNode.LOWER_CASE));
+                        relNode.addOperand(factory.createPropertyFunctionQueryNode(
+                                relNode, PropertyFunctionQueryNode.LOWER_CASE));
                         // get property name
                         node.jjtGetChild(1).jjtAccept(this, relNode);
                     } else {
@@ -957,7 +973,8 @@
                 if (node.jjtGetNumChildren() == 2) {
                     if (queryNode.getType() == QueryNode.TYPE_RELATION) {
                         RelationQueryNode relNode = (RelationQueryNode) queryNode;
-                        relNode.addOperand(new PropertyFunctionQueryNode(relNode, PropertyFunctionQueryNode.UPPER_CASE));
+                        relNode.addOperand(factory.createPropertyFunctionQueryNode(
+                                relNode, PropertyFunctionQueryNode.UPPER_CASE));
                         // get property name
                         node.jjtGetChild(1).jjtAccept(this, relNode);
                     } else {
@@ -970,7 +987,7 @@
                 if (node.jjtGetNumChildren() == 3) {
                     if (queryNode instanceof NAryQueryNode) {
                         NAryQueryNode parent = (NAryQueryNode) queryNode;
-                        RelationQueryNode rel = new RelationQueryNode(
+                        RelationQueryNode rel = factory.createRelationQueryNode(
                                 parent, RelationQueryNode.OPERATION_SIMILAR);
                         parent.addOperand(rel);
                         // assign path

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/PathQueryNodeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/PathQueryNodeTest.java?rev=570095&r1=570094&r2=570095&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/PathQueryNodeTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/PathQueryNodeTest.java Mon Aug 27 05:56:01 2007
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.core.query;
 
+import java.util.Arrays;
+
 import junit.framework.TestCase;
 
 import org.apache.jackrabbit.core.query.xpath.XPathQueryBuilder;
@@ -24,44 +26,59 @@
 
 public class PathQueryNodeTest extends TestCase {
 
+    private static final DefaultQueryNodeFactory QUERY_NODE_FACTORY = new DefaultQueryNodeFactory(
+            Arrays.asList(new QName[] { QName.NT_NODETYPE }));
+    
     private static final NamespaceResolver JCR_RESOLVER = new NamespaceResolver() {
         public String getJCRName(QName qName) {
-            return this.getPrefix(qName.getNamespaceURI()) + ":"
-                    + qName.getLocalName();
+            throw new UnsupportedOperationException();
         }
 
         public String getPrefix(String uri) {
-            return QName.NS_JCR_PREFIX;
+            throw new UnsupportedOperationException();
         }
 
         public QName getQName(String jcrName) {
-            return new QName(QName.NS_JCR_URI,
-                    jcrName.substring(jcrName.indexOf(':')));
+            throw new UnsupportedOperationException();
         }
 
         public String getURI(String prefix) {
-            return QName.NS_JCR_URI;
+            if (QName.NS_JCR_PREFIX.equals(prefix))
+                return QName.NS_JCR_URI;
+            if (QName.NS_NT_PREFIX.equals(prefix))
+                return QName.NS_NT_URI;
+            return "";
         }
     };    
     
     public void testNeedsSystemTree() throws Exception {
-        QueryRootNode queryRootNode = XPathQueryBuilder.createQuery("/jcr:root/*", JCR_RESOLVER);
+        QueryRootNode queryRootNode = XPathQueryBuilder.createQuery("/jcr:root/*", JCR_RESOLVER, QUERY_NODE_FACTORY);
         assertTrue(queryRootNode.needsSystemTree());
 
-        queryRootNode = XPathQueryBuilder.createQuery("/jcr:root/test/*", JCR_RESOLVER);
+        queryRootNode = XPathQueryBuilder.createQuery("/jcr:root/test/*", JCR_RESOLVER, QUERY_NODE_FACTORY);
         assertFalse(queryRootNode.needsSystemTree());
 
-        queryRootNode = XPathQueryBuilder.createQuery("*", JCR_RESOLVER);
+        queryRootNode = XPathQueryBuilder.createQuery("*", JCR_RESOLVER, QUERY_NODE_FACTORY);
         assertTrue(queryRootNode.needsSystemTree());
 
-        queryRootNode = XPathQueryBuilder.createQuery("jcr:system/*", JCR_RESOLVER);
+        queryRootNode = XPathQueryBuilder.createQuery("jcr:system/*", JCR_RESOLVER, QUERY_NODE_FACTORY);
         assertTrue(queryRootNode.needsSystemTree());
 
-        queryRootNode = XPathQueryBuilder.createQuery("test//*", JCR_RESOLVER);
+        queryRootNode = XPathQueryBuilder.createQuery("test//*", JCR_RESOLVER, QUERY_NODE_FACTORY);
         assertFalse(queryRootNode.needsSystemTree());
         
-        queryRootNode = XPathQueryBuilder.createQuery("//test/*", JCR_RESOLVER);
+        queryRootNode = XPathQueryBuilder.createQuery("//test/*", JCR_RESOLVER, QUERY_NODE_FACTORY);
         assertTrue(queryRootNode.needsSystemTree());         
     }
     
+    public void testNeedsSystemTreeForAllNodesByNodeType() throws Exception {
+        QueryRootNode queryRootNode = XPathQueryBuilder.createQuery("//element(*, nt:resource)", JCR_RESOLVER, QUERY_NODE_FACTORY);
+        assertFalse(queryRootNode.needsSystemTree());
+
+        queryRootNode = XPathQueryBuilder.createQuery("//element(*, nt:resource)[@jcr:test = 'foo']", JCR_RESOLVER, QUERY_NODE_FACTORY);
+        assertFalse(queryRootNode.needsSystemTree());
+
+        queryRootNode = XPathQueryBuilder.createQuery("//element(*, nt:nodeType)", JCR_RESOLVER, QUERY_NODE_FACTORY);
+        assertTrue(queryRootNode.needsSystemTree());
+    }
 }