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 2009/04/27 14:43:31 UTC

svn commit: r768954 [1/4] - in /jackrabbit/trunk: jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/query/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query...

Author: mreutegg
Date: Mon Apr 27 12:43:28 2009
New Revision: 768954

URL: http://svn.apache.org/viewvc?rev=768954&view=rev
Log:
JCR-2076: JSR 283: Joins

Added:
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/query/
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/query/Row.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FilterMultiColumnQuery.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JoinQuery.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactoryImpl.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQuery.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryAdapter.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryResult.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingleColumnQueryResult.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/AndConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/ChildNodeConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/ComparisonConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/Constraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/ConstraintBuilder.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/DescendantNodeConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/DynamicOperand.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/EvaluationContext.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/FullTextConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/HierarchyConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/LengthOperand.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/LikeConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/LowerCaseOperand.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/NodeLocalNameOperand.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/NodeNameOperand.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/NotConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/OrConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/PropertyExistenceConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/PropertyValueOperand.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/QueryConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SameNodeConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/SelectorBasedConstraint.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/UpperCaseOperand.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AbstractCondition.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorNodeJoin.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/AncestorPathNodeJoin.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ChildNodeJoin.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Condition.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantNodeJoin.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/DescendantPathNodeJoin.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/EquiJoin.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/Join.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ParentNodeJoin.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/SameNodeJoin.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/ScoreNodeMap.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/
      - copied from r768218, jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/query/qom/
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractJoinTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/DescendantNodeJoinConditionTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/EquiJoinConditionTest.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/SameNodeJoinConditionTest.java   (with props)
Removed:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JQOM2LuceneQueryBuilder.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.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/QueryObjectModelImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNode.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/lucene/SharedFieldCache.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedLuceneQueryHits.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Util.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/WildcardTermEnum.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/AbstractQOMTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/BindVariableValueTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/ChildNodeTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/DescendantNodeTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/LengthTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/NodeLocalNameTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/NodeNameTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/PropertyExistenceTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/QueryObjectModelFactoryTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/SameNodeTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/SelectorTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/TestAll.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/jsr283/query/qom/UpperLowerCaseTest.java
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/qom/ChildNodeJoinConditionImpl.java
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/qom/DescendantNodeJoinConditionImpl.java
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/qom/EquiJoinConditionImpl.java
    jackrabbit/trunk/jackrabbit-spi-commons/src/main/java/org/apache/jackrabbit/spi/commons/query/qom/SameNodeJoinConditionImpl.java

Added: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/query/Row.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/query/Row.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/query/Row.java (added)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/query/Row.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,132 @@
+/*
+ * 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.api.jsr283.query;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Node;
+
+/**
+ * <code>Row</code>...
+ */
+public interface Row extends javax.jcr.query.Row {
+
+    /**
+     * Returns the <code>Node</code> corresponding to this <code>Row</code>.
+     * <p>
+     * A <code>RepositoryException</code> is thrown if this <code>Row</code>
+     * contains values from more than one node. This will be the case when more
+     * than one selector is included among the columns specified for the query.
+     *
+     * @return a <code>Node</code>
+     * @throws RepositoryException if this query has more than one selector
+     * (and therefore, this <code>Row</code> corresponds to more than one
+     * <code>Node</code>) or if another error occurs.
+     * @since JCR 2.0
+     */
+    public Node getNode() throws RepositoryException;
+
+    /**
+     * Returns the <code>Node</code> corresponding to this <code>Row</code> and
+     * the specified selector. If this <code>Row</code> is from a result involving
+     * outer joins, it may have no <code>Node</code> corresponding to the specified selector.
+     * In such a case this method returns <code>null</code>.
+     *
+     * @param selectorName a <code>String</code>
+     * @return a <code>Node</code>
+     * @throws RepositoryException if <code>selectorName</code> is not the alias
+     * of a selector in this query or if another error occurs.
+     * @since JCR 2.0
+     */
+    public Node getNode(String selectorName) throws RepositoryException;
+
+    /**
+     * Equivalent to <code>Row.getNode().getPath()</code>. However, some
+     * implementations may be able gain efficiency by not resolving the actual
+     * <code>Node</code>.
+     *
+     * @return a <code>String</code>
+     * @throws RepositoryException if this query has more than one selector
+     * (and therefore, this <code>Row</code> corresponds to more than one
+     * <code>Node</code>) or if another error occurs.
+     * @since JCR 2.0
+     */
+    public String getPath() throws RepositoryException;
+
+    /**
+     * Equivalent to <code>Row.getNode(selectorName).getPath()</code>. However, some
+     * implementations may be able gain efficiency by not resolving the actual
+     * <code>Node</code>. If this <code>Row</code> is from a result involving
+     * outer joins, it may have no <code>Node</code> corresponding to the specified
+     * selector. In such a case this method returns <code>null</code>.
+     *
+     * @param selectorName a <code>String</code>
+     * @return a <code>String</code>
+     * @throws RepositoryException if <code>selectorName</code> is not the alias
+     * of a selector in this query or if another error occurs.
+     * @since JCR 2.0
+     */
+    public String getPath(String selectorName) throws RepositoryException;
+
+    /**
+     * Returns the full text search score for this row associated with the
+     * default selector. This corresponds to the score of a particular node.
+     * <p>
+     * If no <code>FullTextSearchScore</code> AQM object is associated with the
+     * default selector this method will still return a value. However, in that
+     * case the returned value may not be meaningful or may simply reflect the
+     * minimum possible relevance level (for example, in some systems this might
+     * be a score of 0).
+     * <p>
+     * Note, in JCR-SQL2 a <code>FullTextSearchScore</code> AQM object is represented
+     * by a <code>SCORE()</code> function. In JCR-JQOM it is represented by a
+     * Java object of type <code>javax.jcr.query.qom.FullTextSearchScore</code>.
+     *
+     * @return a <code>double</code>
+     * @throws RepositoryException if this query has more than one selector
+     * (and therefore, this <code>Row</code> corresponds to more than one
+     * <code>Node</code>) or if another error occurs.
+     * @since JCR 2.0
+     */
+    public double getScore() throws RepositoryException;
+
+    /**
+     * Returns the full text search score for this row associated with the
+     * specified selector. This corresponds to the score of a particular node.
+     * <p>
+     * If no <code>FullTextSearchScore</code> AQM object is associated with the
+     * selector <code>selectorName</code> this method will still return a value.
+     * However, in that case the returned value may not be meaningful or may
+     * simply reflect the minimum possible relevance level (for example, in some
+     * systems this might be a score of 0).
+     * <p>
+     * Note, in JCR-SQL2 a <code>FullTextSearchScore</code> AQM object is represented
+     * by a <code>SCORE()</code> function. In JCR-JQOM it is represented by a
+     * Java object of type <code>javax.jcr.query.qom.FullTextSearchScore</code>.
+     * <p>
+     * If this <code>Row</code> is from a result involving
+     * outer joins, it may have no <code>Node</code> corresponding to the specified selector.
+     * In such a case this method returns an implementation selected value, as it would if there were no
+     * <code>FullTextSearchScore</code> associated with the selector.
+     *
+     * @param selectorName a <code>String</code>
+     * @return a <code>double</code>
+     * @throws RepositoryException if <code>selectorName</code> is not the alias
+     * of a selector in this query or if another error occurs.
+     * @since JCR 2.0
+     */
+    public double getScore(String selectorName) throws RepositoryException;
+}

Propchange: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jsr283/query/Row.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java Mon Apr 27 12:43:28 2009
@@ -162,9 +162,4 @@
      *         /jcr:system to be queried; <code>false</code> otherwise.
      */
     public abstract boolean needsSystemTree();
-
-    /**
-     * @return the selector names for this query.
-     */
-    public abstract Name[] getSelectorNames();
 }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FilterMultiColumnQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FilterMultiColumnQuery.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FilterMultiColumnQuery.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FilterMultiColumnQuery.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,89 @@
+/*
+ * 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.lucene;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.jackrabbit.core.query.lucene.constraint.Constraint;
+import org.apache.lucene.search.Sort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * <code>FilterMultiColumnQuery</code> wraps a multi column query and filters
+ * out rows that do not satisfy a given constraint.
+ */
+public class FilterMultiColumnQuery implements MultiColumnQuery {
+
+    /**
+     * The logger instance for this class.
+     */
+    private static final Logger log = LoggerFactory.getLogger(FilterMultiColumnQuery.class);
+
+    /**
+     * The query to filter.
+     */
+    private final MultiColumnQuery query;
+
+    /**
+     * The constraint for filtering.
+     */
+    private final Constraint constraint;
+
+    /**
+     * Creates a new filter multi column query for the given <code>query</code>
+     * and <code>constraint</code>.
+     *
+     * @param query      the query to filter.
+     * @param constraint the constraint for filtering.
+     */
+    public FilterMultiColumnQuery(MultiColumnQuery query,
+                                  Constraint constraint) {
+        this.query = query;
+        this.constraint = constraint;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public MultiColumnQueryHits execute(final JackrabbitIndexSearcher searcher,
+                                        Sort sort,
+                                        long resultFetchHint)
+            throws IOException {
+        return new FilterMultiColumnQueryHits(query.execute(
+                searcher, sort, resultFetchHint)) {
+
+            {
+                log.debug(Arrays.asList(getSelectorNames()).toString());
+            }
+
+            public ScoreNode[] nextScoreNodes() throws IOException {
+                ScoreNode[] next;
+                do {
+                    next = super.nextScoreNodes();
+                    if (log.isDebugEnabled()) {
+                        if (next != null) {
+                            log.debug(Arrays.asList(next).toString());
+                        }
+                    }
+                } while (next != null && !constraint.evaluate(next, getSelectorNames(), searcher));
+                return next;
+            }
+        };
+    }
+}

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

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JackrabbitIndexSearcher.java Mon Apr 27 12:43:28 2009
@@ -20,7 +20,10 @@
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.Sort;
 import org.apache.lucene.index.IndexReader;
+import org.apache.jackrabbit.core.query.lucene.constraint.EvaluationContext;
 import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.state.ItemStateManager;
+import org.apache.jackrabbit.spi.Name;
 
 import java.io.IOException;
 
@@ -28,7 +31,9 @@
  * <code>JackrabbitIndexSearcher</code> implements an index searcher with
  * jackrabbit specific optimizations.
  */
-public class JackrabbitIndexSearcher extends IndexSearcher {
+public class JackrabbitIndexSearcher
+        extends IndexSearcher
+        implements EvaluationContext {
 
     /**
      * The session that executes the query.
@@ -41,15 +46,24 @@
     private final IndexReader reader;
 
     /**
+     * The item state manager of the workspace.
+     */
+    private final ItemStateManager ism;
+
+    /**
      * Creates a new jackrabbit index searcher.
      *
      * @param s the session that executes the query.
      * @param r the index reader.
+     * @param ism the shared item state manager.
      */
-    public JackrabbitIndexSearcher(SessionImpl s, IndexReader r) {
+    public JackrabbitIndexSearcher(SessionImpl s,
+                                   IndexReader r,
+                                   ItemStateManager ism) {
         super(r);
         this.session = s;
         this.reader = r;
+        this.ism = ism;
     }
 
     /**
@@ -58,15 +72,17 @@
      * @param query           the query to execute.
      * @param sort            the sort criteria.
      * @param resultFetchHint a hint on how many results should be fetched.
+     * @param selectorName    the single selector name for the query hits.
      * @return the query hits.
      * @throws IOException if an error occurs while executing the query.
      */
     public MultiColumnQueryHits execute(Query query,
                                         Sort sort,
-                                        long resultFetchHint)
+                                        long resultFetchHint,
+                                        Name selectorName)
             throws IOException {
-        return new QueryHitsAdapter(evaluate(query, sort, resultFetchHint),
-                QueryImpl.DEFAULT_SELECTOR_NAME);
+        return new QueryHitsAdapter(
+                evaluate(query, sort, resultFetchHint), selectorName);
     }
 
     /**
@@ -96,6 +112,8 @@
         return hits;
     }
 
+    //------------------------< EvaluationContext >-----------------------------
+
     /**
      * Evaluates the query and returns the hits that match the query.
      *
@@ -106,4 +124,18 @@
     public QueryHits evaluate(Query query) throws IOException {
         return evaluate(query, new Sort(), Integer.MAX_VALUE);
     }
+
+    /**
+     * @return session that executes the query.
+     */
+    public SessionImpl getSession() {
+        return session;
+    }
+
+    /**
+     * @return the item state manager of the workspace.
+     */
+    public ItemStateManager getItemStateManager() {
+        return ism;
+    }
 }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JoinQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JoinQuery.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JoinQuery.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JoinQuery.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,100 @@
+/*
+ * 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.lucene;
+
+import java.io.IOException;
+
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortComparatorSource;
+import org.apache.lucene.index.IndexReader;
+import org.apache.jackrabbit.core.query.lucene.join.Join;
+import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.spi.commons.query.qom.JoinConditionImpl;
+
+/**
+ * <code>JoinQuery</code> implements a query that performs a join.
+ */
+public class JoinQuery implements MultiColumnQuery {
+
+    /**
+     * The left side of the join.
+     */
+    private final MultiColumnQuery left;
+
+    /**
+     * The right side of the join.
+     */
+    private final MultiColumnQuery right;
+
+    /**
+     * The join type.
+     */
+    private final int joinType;
+
+    /**
+     * The QOM join condition.
+     */
+    private final JoinConditionImpl joinCondition;
+
+    /**
+     * The sort comparator source of the index.
+     */
+    private final SortComparatorSource scs;
+
+    /**
+     * The hierarchy manager of the workspace.
+     */
+    private final HierarchyManager hmgr;
+
+    /**
+     * Creates a new join query.
+     *
+     * @param left          the left side of the query.
+     * @param right         the right side of the query.
+     * @param joinType      the join type.
+     * @param joinCondition the join condition.
+     * @param scs           the sort comparator source of the index.
+     * @param hmgr          the hierarchy manager of the workspace.
+     */
+    public JoinQuery(MultiColumnQuery left,
+                     MultiColumnQuery right,
+                     int joinType,
+                     JoinConditionImpl joinCondition,
+                     SortComparatorSource scs,
+                     HierarchyManager hmgr) {
+        this.left = left;
+        this.right = right;
+        this.joinType = joinType;
+        this.joinCondition = joinCondition;
+        this.scs = scs;
+        this.hmgr = hmgr;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public MultiColumnQueryHits execute(JackrabbitIndexSearcher searcher,
+                                        Sort sort,
+                                        long resultFetchHint)
+            throws IOException {
+        IndexReader reader = searcher.getIndexReader();
+        HierarchyResolver resolver = (HierarchyResolver) reader;
+        return Join.create(left.execute(searcher, sort, resultFetchHint),
+                right.execute(searcher, sort, resultFetchHint),
+                joinType, joinCondition, reader, resolver, scs, hmgr);
+    }
+}

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

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,78 @@
+/*
+ * 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.lucene;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.lucene.search.Query;
+import org.apache.jackrabbit.spi.commons.query.qom.SelectorImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.FullTextSearchImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.PropertyExistenceImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.SourceImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.JoinImpl;
+
+/**
+ * <code>LuceneQueryFactory</code> implements a factory that creates lucene
+ * queries from given QOM elements.
+ */
+public interface LuceneQueryFactory {
+
+    /**
+     * Creates a lucene query for the given QOM selector.
+     *
+     * @param selector the selector.
+     * @return a lucene query for the given selector.
+     * @throws RepositoryException if an error occurs while creating the query.
+     */
+    public Query create(SelectorImpl selector) throws RepositoryException;
+
+    /**
+     * Creates a lucene query for the given QOM full text search.
+     *
+     * @param constraint the full text search constraint.
+     * @return the lucene query for the given constraint.
+     * @throws RepositoryException if an error occurs while creating the query.
+     */
+    public Query create(FullTextSearchImpl constraint) throws RepositoryException;
+
+    /**
+     * Creates a lucene query for the given QOM property existence constraint.
+     *
+     * @param constraint the QOM constraint.
+     * @return the lucene query for the given constraint.
+     * @throws RepositoryException if an error occurs while creating the query.
+     */
+    public Query create(PropertyExistenceImpl constraint) throws RepositoryException;
+
+    /**
+     * Creates a multi column query for the given QOM source.
+     *
+     * @param source the QOM source.
+     * @return a multi column query for the given source.
+     * @throws RepositoryException if an error occurs while creating the query.
+     */
+    public MultiColumnQuery create(SourceImpl source) throws RepositoryException;
+
+    /**
+     * Creates a multi column query for the given QOM join.
+     *
+     * @param join the QOM join.
+     * @return the multi column query for the given join.
+     * @throws RepositoryException if an error occurs while creating the query.
+     */
+    public MultiColumnQuery create(JoinImpl join) throws RepositoryException;
+}

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

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactoryImpl.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactoryImpl.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactoryImpl.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,255 @@
+/*
+ * 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.lucene;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.RepositoryException;
+
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.SortComparatorSource;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.jackrabbit.spi.commons.query.qom.SelectorImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.FullTextSearchImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.PropertyExistenceImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.SourceImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.JoinImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.DefaultQOMTreeVisitor;
+import org.apache.jackrabbit.spi.commons.query.qom.JoinConditionImpl;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.HierarchyManager;
+
+/**
+ * <code>LuceneQueryFactoryImpl</code> implements a lucene query factory.
+ */
+public class LuceneQueryFactoryImpl implements LuceneQueryFactory {
+
+    /**
+     * Session of the user executing this query
+     */
+    private final SessionImpl session;
+
+    /**
+     * The source comparator source.
+     */
+    private final SortComparatorSource scs;
+
+    /**
+     * The hierarchy manager.
+     */
+    private final HierarchyManager hmgr;
+
+    /**
+     * Namespace mappings to internal prefixes
+     */
+    private final NamespaceMappings nsMappings;
+
+    /**
+     * NamePathResolver to map namespace mappings to internal prefixes
+     */
+    private final NamePathResolver npResolver;
+
+    /**
+     * The analyzer instance to use for contains function query parsing
+     */
+    private final Analyzer analyzer;
+
+    /**
+     * The synonym provider or <code>null</code> if none is configured.
+     */
+    private final SynonymProvider synonymProvider;
+
+    /**
+     * The index format version.
+     */
+    private final IndexFormatVersion version;
+
+    /**
+     * Creates a new lucene query factory.
+     *
+     * @param session         the session that executes the query.
+     * @param scs             the sort comparator source of the index.
+     * @param hmgr            the hierarchy manager of the workspace.
+     * @param nsMappings      the index internal namespace mappings.
+     * @param analyzer        the analyzer of the index.
+     * @param synonymProvider the synonym provider of the index.
+     * @param version         the version of the index format.
+     */
+    public LuceneQueryFactoryImpl(SessionImpl session,
+                                  SortComparatorSource scs,
+                                  HierarchyManager hmgr,
+                                  NamespaceMappings nsMappings,
+                                  Analyzer analyzer,
+                                  SynonymProvider synonymProvider,
+                                  IndexFormatVersion version) {
+        this.session = session;
+        this.scs = scs;
+        this.hmgr = hmgr;
+        this.nsMappings = nsMappings;
+        this.analyzer = analyzer;
+        this.synonymProvider = synonymProvider;
+        this.version = version;
+        this.npResolver = NamePathResolverImpl.create(nsMappings);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Query create(SelectorImpl selector) throws RepositoryException {
+        List terms = new ArrayList();
+        String mixinTypesField = npResolver.getJCRName(NameConstants.JCR_MIXINTYPES);
+        String primaryTypeField = npResolver.getJCRName(NameConstants.JCR_PRIMARYTYPE);
+
+        NodeTypeManager ntMgr = session.getWorkspace().getNodeTypeManager();
+        NodeType base = null;
+        try {
+            base = ntMgr.getNodeType(session.getJCRName(selector.getNodeTypeQName()));
+        } catch (RepositoryException e) {
+            // node type does not exist
+        }
+
+        if (base != null && base.isMixin()) {
+            // search for nodes where jcr:mixinTypes is set to this mixin
+            Term t = new Term(FieldNames.PROPERTIES,
+                    FieldNames.createNamedValue(mixinTypesField,
+                            npResolver.getJCRName(selector.getNodeTypeQName())));
+            terms.add(t);
+        } else {
+            // search for nodes where jcr:primaryType is set to this type
+            Term t = new Term(FieldNames.PROPERTIES,
+                    FieldNames.createNamedValue(primaryTypeField,
+                            npResolver.getJCRName(selector.getNodeTypeQName())));
+            terms.add(t);
+        }
+
+        // now search for all node types that are derived from base
+        if (base != null) {
+            NodeTypeIterator allTypes = ntMgr.getAllNodeTypes();
+            while (allTypes.hasNext()) {
+                NodeType nt = allTypes.nextNodeType();
+                NodeType[] superTypes = nt.getSupertypes();
+                if (Arrays.asList(superTypes).contains(base)) {
+                    Name n = session.getQName(nt.getName());
+                    String ntName = nsMappings.translateName(n);
+                    Term t;
+                    if (nt.isMixin()) {
+                        // search on jcr:mixinTypes
+                        t = new Term(FieldNames.PROPERTIES,
+                                FieldNames.createNamedValue(mixinTypesField, ntName));
+                    } else {
+                        // search on jcr:primaryType
+                        t = new Term(FieldNames.PROPERTIES,
+                                FieldNames.createNamedValue(primaryTypeField, ntName));
+                    }
+                    terms.add(t);
+                }
+            }
+        }
+        Query q;
+        if (terms.size() == 1) {
+            q = new JackrabbitTermQuery((Term) terms.get(0));
+        } else {
+            BooleanQuery b = new BooleanQuery();
+            for (Iterator it = terms.iterator(); it.hasNext();) {
+                b.add(new JackrabbitTermQuery((Term) it.next()), BooleanClause.Occur.SHOULD);
+            }
+            q = b;
+        }
+        return q;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Query create(FullTextSearchImpl fts) throws RepositoryException {
+        String fieldname;
+        if (fts.getPropertyName() == null) {
+            // fulltext on node
+            fieldname = FieldNames.FULLTEXT;
+        } else {
+            // final path element is a property name
+            Name propName = fts.getPropertyQName();
+            StringBuffer tmp = new StringBuffer();
+            tmp.append(nsMappings.getPrefix(propName.getNamespaceURI()));
+            tmp.append(":").append(FieldNames.FULLTEXT_PREFIX);
+            tmp.append(propName.getLocalName());
+            fieldname = tmp.toString();
+        }
+        QueryParser parser = new JackrabbitQueryParser(
+                fieldname, analyzer, synonymProvider);
+        try {
+            return parser.parse(fts.getFullTextSearchExpression());
+        } catch (ParseException e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Query create(PropertyExistenceImpl prop) throws RepositoryException {
+        String propName = npResolver.getJCRName(prop.getPropertyQName());
+        return Util.createMatchAllQuery(propName, version);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public MultiColumnQuery create(SourceImpl source) throws RepositoryException {
+        // source is either selector or join
+        try {
+            return (MultiColumnQuery) source.accept(new DefaultQOMTreeVisitor() {
+                public Object visit(JoinImpl node, Object data) throws Exception {
+                    return create(node);
+                }
+
+                public Object visit(SelectorImpl node, Object data) throws Exception {
+                    return MultiColumnQueryAdapter.adapt(
+                            create(node), node.getSelectorQName());
+                }
+            }, null);
+        } catch (RepositoryException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RepositoryException(e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public MultiColumnQuery create(JoinImpl join) throws RepositoryException {
+        MultiColumnQuery left = create((SourceImpl) join.getLeft());
+        MultiColumnQuery right = create((SourceImpl) join.getRight());
+        return new JoinQuery(left, right, join.getJoinType(),
+                (JoinConditionImpl) join.getJoinCondition(), scs, hmgr);
+    }
+}

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

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryHits.java Mon Apr 27 12:43:28 2009
@@ -57,9 +57,10 @@
         if (!scorer.next()) {
             return null;
         }
-        String uuid = reader.document(scorer.doc()).get(FieldNames.UUID);
+        int doc = scorer.doc();
+        String uuid = reader.document(doc).get(FieldNames.UUID);
         NodeId id = new NodeId(UUID.fromString(uuid));
-        return new ScoreNode(id, scorer.score());
+        return new ScoreNode(id, scorer.score(), doc);
     }
 
     /**

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQuery.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQuery.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQuery.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.query.lucene;
+
+import java.io.IOException;
+
+import org.apache.lucene.search.Sort;
+
+/**
+ * <code>MultiColumnQuery</code> defines an interface for a query that returns
+ * {@link MultiColumnQueryHits}.
+ */
+public interface MultiColumnQuery {
+
+    /**
+     * Executes this query and returns multi column query hits.
+     *
+     * @param searcher        the index searcher.
+     * @param sort            the sort criteria.
+     * @param resultFetchHint the result fetch hint.
+     * @return the query hits.
+     * @throws IOException if an error occurs while executing the query.
+     */
+    public MultiColumnQueryHits execute(JackrabbitIndexSearcher searcher,
+                                        Sort sort,
+                                        long resultFetchHint)
+            throws IOException;
+}

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

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryAdapter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryAdapter.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryAdapter.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryAdapter.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,72 @@
+/*
+ * 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.lucene;
+
+import java.io.IOException;
+
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Sort;
+import org.apache.jackrabbit.spi.Name;
+
+/**
+ * <code>MultiColumnQueryAdapter</code> adapts a lucene query to act like a
+ * {@link MultiColumnQuery}.
+ */
+public class MultiColumnQueryAdapter implements MultiColumnQuery {
+
+    /**
+     * The underlying lucene query.
+     */
+    private final Query query;
+
+    /**
+     * The selector name for the query hits.
+     */
+    private final Name selectorName;
+
+    /**
+     * Creates a new adapter for the given <code>query</code>.
+     *
+     * @param query        a lucene query.
+     * @param selectorName the selector name for the query hits.
+     */
+    private MultiColumnQueryAdapter(Query query, Name selectorName) {
+        this.query = query;
+        this.selectorName = selectorName;
+    }
+
+    /**
+     * Adapts the given <code>query</code>.
+     *
+     * @param query        the lucene query to adapt.
+     * @param selectorName the selector name for the query hits.
+     * @return a {@link MultiColumnQuery} that wraps the given lucene query.
+     */
+    public static MultiColumnQuery adapt(Query query, Name selectorName) {
+        return new MultiColumnQueryAdapter(query, selectorName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public MultiColumnQueryHits execute(JackrabbitIndexSearcher searcher,
+                                        Sort sort,
+                                        long resultFetchHint)
+            throws IOException {
+        return searcher.execute(query, sort, resultFetchHint, selectorName);
+    }
+}

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

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryResult.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryResult.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryResult.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryResult.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,76 @@
+/*
+ * 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.lucene;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.ItemManager;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+
+/**
+ * <code>MultiColumnQueryResult</code> implements a query result that executes
+ * a {@link MultiColumnQuery}.
+ */
+public class MultiColumnQueryResult extends QueryResultImpl {
+
+    /**
+     * The query to execute.
+     */
+    private final MultiColumnQuery query;
+
+    public MultiColumnQueryResult(SearchIndex index,
+                                  ItemManager itemMgr,
+                                  SessionImpl session,
+                                  AccessManager accessMgr,
+                                  AbstractQueryImpl queryImpl,
+                                  MultiColumnQuery query,
+                                  SpellSuggestion spellSuggestion,
+                                  Name[] selectProps,
+                                  Path[] orderProps,
+                                  boolean[] orderSpecs,
+                                  boolean documentOrder,
+                                  long offset,
+                                  long limit) throws RepositoryException {
+        super(index, itemMgr, session, accessMgr, queryImpl, spellSuggestion,
+                selectProps, orderProps, orderSpecs, documentOrder, offset, limit);
+        this.query = query;
+        // if document order is requested get all results right away
+        getResults(docOrder ? Integer.MAX_VALUE : index.getResultFetchSize());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected MultiColumnQueryHits executeQuery(long resultFetchHint)
+            throws IOException {
+        return index.executeQuery(session, query, orderProps,
+                orderSpecs, resultFetchHint);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected ExcerptProvider createExcerptProvider() throws IOException {
+        // TODO
+        return null;
+    }
+}

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

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java Mon Apr 27 12:43:28 2009
@@ -853,18 +853,12 @@
     protected void addLength(Document doc,
                              String propertyName,
                              InternalValue value) {
-        long length;
-        if (value.getType() == PropertyType.BINARY) {
-            length = value.getBLOBFileValue().getLength();
-        } else if (value.getType() == PropertyType.NAME
-                || value.getType() == PropertyType.PATH) {
-            return;
-        } else {
-            length = value.toString().length();
+        long length = Util.getLength(value);
+        if (length != -1) {
+            doc.add(new Field(FieldNames.PROPERTY_LENGTHS,
+                    FieldNames.createNamedLength(propertyName, length),
+                    Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS));
         }
-        doc.add(new Field(FieldNames.PROPERTY_LENGTHS,
-                FieldNames.createNamedLength(propertyName, length),
-                Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS));
     }
 
     /**

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=768954&r1=768953&r2=768954&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 Apr 27 12:43:28 2009
@@ -128,7 +128,7 @@
             ascSpecs[i] = orderSpecs[i].isAscending();
         }
 
-        return new QueryResultImpl(index, itemMgr,
+        return new SingleColumnQueryResult(index, itemMgr,
                 session, session.getAccessManager(),
                 this, query, new SpellSuggestion(index.getSpellChecker(), root),
                 getSelectProperties(), orderProperties, ascSpecs,
@@ -195,10 +195,4 @@
         return this.root.needsSystemTree();
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public Name[] getSelectorNames() {
-        return new Name[]{DEFAULT_SELECTOR_NAME};
-    }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java Mon Apr 27 12:43:28 2009
@@ -17,6 +17,8 @@
 package org.apache.jackrabbit.core.query.lucene;
 
 import org.apache.jackrabbit.core.query.PropertyTypeRegistry;
+import org.apache.jackrabbit.core.query.lucene.constraint.ConstraintBuilder;
+import org.apache.jackrabbit.core.query.lucene.constraint.Constraint;
 import org.apache.jackrabbit.spi.commons.query.jsr283.qom.QueryObjectModelConstants;
 import org.apache.jackrabbit.spi.commons.query.jsr283.qom.PropertyValue;
 import org.apache.jackrabbit.spi.commons.query.qom.QueryObjectModelTree;
@@ -24,13 +26,11 @@
 import org.apache.jackrabbit.spi.commons.query.qom.OrderingImpl;
 import org.apache.jackrabbit.spi.commons.query.qom.DefaultTraversingQOMTreeVisitor;
 import org.apache.jackrabbit.spi.commons.query.qom.BindVariableValueImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.SelectorImpl;
 import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.ItemManager;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
-import org.apache.lucene.search.Query;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
@@ -77,22 +77,10 @@
         return true;
     }
 
-    /**
-     * {@inheritDoc}
-     */ 
-    public Name[] getSelectorNames() {
-        SelectorImpl[] selectors = qomTree.getSource().getSelectors();
-        Name[] names = new Name[selectors.length];
-        for (int i = 0; i < names.length; i++) {
-            names[i] = selectors[i].getSelectorQName();
-        }
-        return names;
-    }
-
     //-------------------------< ExecutableQuery >------------------------------
 
     /**
-     * Executes this query and returns a <code>{@link javax.jcr.query.QueryResult}</code>.
+     * Executes this query and returns a <code>{@link QueryResult}</code>.
      *
      * @param offset the offset in the total result set
      * @param limit  the maximum result size
@@ -101,11 +89,22 @@
      */
     public QueryResult execute(long offset, long limit)
             throws RepositoryException {
-        Query query = JQOM2LuceneQueryBuilder.createQuery(qomTree, session,
-                index.getContext().getItemStateManager(),
+
+        LuceneQueryFactory factory = new LuceneQueryFactoryImpl(session,
+                index.getSortComparatorSource(),
+                index.getContext().getHierarchyManager(),
                 index.getNamespaceMappings(), index.getTextAnalyzer(),
-                propReg, index.getSynonymProvider(), getBindVariableValues(),
-                index.getIndexFormatVersion());
+                index.getSynonymProvider(), index.getIndexFormatVersion());
+
+        MultiColumnQuery query = factory.create(qomTree.getSource());
+
+        if (qomTree.getConstraint() != null) {
+            Constraint c = ConstraintBuilder.create(qomTree.getConstraint(),
+                    getBindVariableValues(), qomTree.getSource().getSelectors(),
+                    factory, session.getValueFactory());
+            query = new FilterMultiColumnQuery(query, c);
+        }
+
 
         ColumnImpl[] columns = qomTree.getColumns();
         Name[] selectProps = new Name[columns.length];
@@ -126,7 +125,7 @@
                         orderings[i].getOperand() + " not yet implemented");
             }
         }
-        return new QueryResultImpl(index, itemMgr,
+        return new MultiColumnQueryResult(index, itemMgr,
                 session, session.getAccessManager(),
                 // TODO: spell suggestion missing
                 this, query, null, selectProps, orderProps, orderSpecs,

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java Mon Apr 27 12:43:28 2009
@@ -21,7 +21,6 @@
 import org.apache.jackrabbit.core.security.AccessManager;
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.Path;
-import org.apache.lucene.search.Query;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,9 +36,9 @@
 import java.util.NoSuchElementException;
 
 /**
- * Implements the <code>javax.jcr.query.QueryResult</code> interface.
+ * Implements the <code>QueryResult</code> interface.
  */
-public class QueryResultImpl implements QueryResult {
+public abstract class QueryResultImpl implements QueryResult {
 
     /**
      * The logger instance for this class
@@ -49,12 +48,12 @@
     /**
      * The search index to execute the query.
      */
-    private final SearchIndex index;
+    protected final SearchIndex index;
 
     /**
      * The item manager of the session executing the query
      */
-    private final ItemManager itemMgr;
+    protected final ItemManager itemMgr;
 
     /**
      * The session executing the query
@@ -64,7 +63,7 @@
     /**
      * The access manager of the session that executes the query.
      */
-    private final AccessManager accessMgr;
+    protected final AccessManager accessMgr;
 
     /**
      * The query instance which created this query result.
@@ -72,11 +71,6 @@
     protected final AbstractQueryImpl queryImpl;
 
     /**
-     * The lucene query to execute.
-     */
-    protected final Query query;
-
-    /**
      * The spell suggestion or <code>null</code> if not available.
      */
     protected final SpellSuggestion spellSuggestion;
@@ -112,6 +106,12 @@
     private int numResults = -1;
 
     /**
+     * The selector names associated with the score nodes. The selector names
+     * are set when the query is executed via {@link #getResults(long)}.
+     */
+    private Name[] selectorNames;
+
+    /**
      * The number of results that are invalid, either because a node does not
      * exist anymore or because the session does not have access to the node.
      */
@@ -120,7 +120,7 @@
     /**
      * If <code>true</code> nodes are returned in document order.
      */
-    private final boolean docOrder;
+    protected final boolean docOrder;
 
     /**
      * The excerpt provider or <code>null</code> if none was created yet.
@@ -138,7 +138,8 @@
     private final long limit;
 
     /**
-     * Creates a new query result.
+     * Creates a new query result. The concrete sub class is responsible for
+     * calling {@link #getResults(long)} after this constructor had been called.
      *
      * @param index           the search index where the query is executed.
      * @param itemMgr         the item manager of the session executing the
@@ -148,7 +149,6 @@
      *                        query.
      * @param queryImpl       the query instance which created this query
      *                        result.
-     * @param query           the lucene query to execute on the index.
      * @param spellSuggestion the spell suggestion or <code>null</code> if none
      *                        is available.
      * @param selectProps     the select properties of the query.
@@ -167,7 +167,6 @@
                            SessionImpl session,
                            AccessManager accessMgr,
                            AbstractQueryImpl queryImpl,
-                           Query query,
                            SpellSuggestion spellSuggestion,
                            Name[] selectProps,
                            Path[] orderProps,
@@ -180,7 +179,6 @@
         this.session = session;
         this.accessMgr = accessMgr;
         this.queryImpl = queryImpl;
-        this.query = query;
         this.spellSuggestion = spellSuggestion;
         this.selectProps = selectProps;
         this.orderProps = orderProps;
@@ -188,8 +186,6 @@
         this.docOrder = orderProps.length == 0 && documentOrder;
         this.offset = offset;
         this.limit = limit;
-        // if document order is requested get all results right away
-        getResults(docOrder ? Integer.MAX_VALUE : index.getResultFetchSize());
     }
 
     /**
@@ -222,13 +218,13 @@
     public RowIterator getRows() throws RepositoryException {
         if (excerptProvider == null) {
             try {
-                excerptProvider = index.createExcerptProvider(query);
+                excerptProvider = createExcerptProvider();
             } catch (IOException e) {
                 throw new RepositoryException(e);
             }
         }
         return new RowIteratorImpl(getScoreNodes(), selectProps,
-                queryImpl.getSelectorNames(), itemMgr,
+                selectorNames, itemMgr,
                 index.getContext().getHierarchyManager(), session,
                 excerptProvider, spellSuggestion);
     }
@@ -241,10 +237,17 @@
      * @return hits for this query result.
      * @throws IOException if an error occurs while executing the query.
      */
-    protected MultiColumnQueryHits executeQuery(long resultFetchHint) throws IOException {
-        return index.executeQuery(session, queryImpl,
-                query, orderProps, orderSpecs, resultFetchHint);
-    }
+    protected abstract MultiColumnQueryHits executeQuery(long resultFetchHint)
+            throws IOException;
+
+    /**
+     * Creates an excerpt provider for this result set.
+     *
+     * @return an excerpt provider.
+     * @throws IOException if an error occurs.
+     */
+    protected abstract ExcerptProvider createExcerptProvider()
+            throws IOException;
 
     //--------------------------------< internal >------------------------------
 
@@ -271,7 +274,7 @@
      * @throws RepositoryException if an error occurs while executing the
      *                             query.
      */
-    private void getResults(long size) throws RepositoryException {
+    protected void getResults(long size) throws RepositoryException {
         if (log.isDebugEnabled()) {
             log.debug("getResults({}) limit={}", new Long(size), new Long(limit));
         }
@@ -295,6 +298,8 @@
             result = executeQuery(maxResultSize);
             log.debug("query executed in {} ms",
                     new Long(System.currentTimeMillis() - time));
+            // set selector names
+            selectorNames = result.getSelectorNames();
 
             if (resultNodes.isEmpty() && offset > 0) {
                 // collect result offset into dummy list

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java Mon Apr 27 12:43:28 2009
@@ -251,7 +251,7 @@
      * Implements the {@link javax.jcr.query.Row} interface, which represents
      * a row in the query result.
      */
-    class RowImpl implements Row {
+    class RowImpl implements org.apache.jackrabbit.api.jsr283.query.Row {
 
         /**
          * The score for this result row

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNode.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNode.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNode.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNode.java Mon Apr 27 12:43:28 2009
@@ -16,13 +16,18 @@
  */
 package org.apache.jackrabbit.core.query.lucene;
 
+import java.io.IOException;
+
 import org.apache.jackrabbit.core.NodeId;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermDocs;
 
 /**
  * <code>ScoreNode</code> implements a simple container which holds a mapping
  * of {@link NodeId} to a score value.
  */
-final class ScoreNode {
+public final class ScoreNode {
 
     /**
      * The id of a node.
@@ -35,14 +40,32 @@
     private final float score;
 
     /**
+     * The lucene document number for this score node. Set to <code>-1</code> if
+     * unknown.
+     */
+    private final int doc;
+
+    /**
      * Creates a new <code>ScoreNode</code>.
      *
      * @param id    the node id.
      * @param score the score value.
      */
-    ScoreNode(NodeId id, float score) {
+    public ScoreNode(NodeId id, float score) {
+        this(id, score, -1);
+    }
+
+    /**
+     * Creates a new <code>ScoreNode</code>.
+     *
+     * @param id    the node id.
+     * @param score the score value.
+     * @param doc   the document number.
+     */
+    public ScoreNode(NodeId id, float score, int doc) {
         this.id = id;
         this.score = score;
+        this.doc = doc;
     }
 
     /**
@@ -58,4 +81,42 @@
     public float getScore() {
         return score;
     }
+
+    /**
+     * Returns the document number for this score node.
+     *
+     * @param reader the current index reader to look up the document if
+     *               needed.
+     * @return the document number.
+     * @throws IOException if an error occurs while reading from the index or
+     *                     the node is not present in the index.
+     */
+    public int getDoc(IndexReader reader) throws IOException {
+        if (doc == -1) {
+            TermDocs docs = reader.termDocs(new Term(FieldNames.UUID, id.toString()));
+            try {
+                if (docs.next()) {
+                    return docs.doc();
+                } else {
+                    throw new IOException("Node with id " + id + " not found in index");
+                }
+            } finally {
+                docs.close();
+            }
+        } else {
+            return doc;
+        }
+    }
+
+    public String toString() {
+        StringBuffer sb = new StringBuffer(id.toString());
+        sb.append("(");
+        if (doc != -1) {
+            sb.append(doc);
+        } else {
+            sb.append("?");
+        }
+        sb.append(")");
+        return sb.toString();
+    }
 }

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=768954&r1=768953&r2=768954&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 Apr 27 12:43:28 2009
@@ -754,10 +754,52 @@
         Sort sort = new Sort(createSortFields(orderProps, orderSpecs));
 
         final IndexReader reader = getIndexReader(queryImpl.needsSystemTree());
-        JackrabbitIndexSearcher searcher = new JackrabbitIndexSearcher(session, reader);
+        JackrabbitIndexSearcher searcher = new JackrabbitIndexSearcher(
+                session, reader, getContext().getItemStateManager());
         searcher.setSimilarity(getSimilarity());
         return new FilterMultiColumnQueryHits(
-                searcher.execute(query, sort, resultFetchHint)) {
+                searcher.execute(query, sort, resultFetchHint,
+                        QueryImpl.DEFAULT_SELECTOR_NAME)) {
+            public void close() throws IOException {
+                try {
+                    super.close();
+                } finally {
+                    PerQueryCache.getInstance().dispose();
+                    Util.closeOrRelease(reader);
+                }
+            }
+        };
+    }
+
+    /**
+     * Executes the query on the search index.
+     *
+     * @param session         the session that executes the query.
+     * @param query           the query.
+     * @param orderProps      name of the properties for sort order.
+     * @param orderSpecs      the order specs for the sort order properties.
+     *                        <code>true</code> indicates ascending order,
+     *                        <code>false</code> indicates descending.
+     * @param resultFetchHint a hint on how many results should be fetched.
+     * @return the query hits.
+     * @throws IOException if an error occurs while searching the index.
+     */
+    public MultiColumnQueryHits executeQuery(SessionImpl session,
+                                             MultiColumnQuery query,
+                                             Path[] orderProps,
+                                             boolean[] orderSpecs,
+                                             long resultFetchHint)
+            throws IOException {
+        checkOpen();
+
+        Sort sort = new Sort(createSortFields(orderProps, orderSpecs));
+
+        final IndexReader reader = getIndexReader();
+        JackrabbitIndexSearcher searcher = new JackrabbitIndexSearcher(
+                session, reader, getContext().getItemStateManager());
+        searcher.setSimilarity(getSimilarity());
+        return new FilterMultiColumnQueryHits(
+                query.execute(searcher, sort, resultFetchHint)) {
             public void close() throws IOException {
                 try {
                     super.close();
@@ -988,6 +1030,13 @@
     }
 
     /**
+     * @return the sort comparator source for this index.
+     */
+    protected SortComparatorSource getSortComparatorSource() {
+        return scs;
+    }
+
+    /**
      * Factory method to create the <code>TextExtractor</code> instance.
      *
      * @return the <code>TextExtractor</code> instance this index should use.

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldCache.java Mon Apr 27 12:43:28 2009
@@ -36,7 +36,7 @@
  * but it only works on the basis of a field name. There is no further control
  * over the terms to iterate, that's why we use our own implementation.
  */
-class SharedFieldCache {
+public class SharedFieldCache {
 
     /**
      * Expert: Stores term text values and document ordering data.

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SharedFieldSortComparator.java Mon Apr 27 12:43:28 2009
@@ -20,8 +20,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import javax.jcr.PropertyType;
-
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.ScoreDoc;
 import org.apache.lucene.search.ScoreDocComparator;
@@ -188,23 +186,7 @@
          *         are equal
          */
         public int compare(ScoreDoc i, ScoreDoc j) {
-            Comparable iTerm = sortValue(i);
-            Comparable jTerm = sortValue(j);
-
-            if (iTerm == jTerm) {
-                return 0;
-            } else if (iTerm == null) {
-                return -1;
-            } else if (jTerm == null) {
-                return 1;
-            } else if (iTerm.getClass() == jTerm.getClass()) {
-                return iTerm.compareTo(jTerm);
-            } else {
-                // differing types -> compare class names
-                String iName = iTerm.getClass().getName();
-                String jName = jTerm.getClass().getName();
-                return iName.compareTo(jName);
-            }
+            return Util.compare(sortValue(i), sortValue(j));
         }
 
         public int sortType() {
@@ -256,11 +238,11 @@
             super(reader);
             this.indexes = new SharedFieldCache.ValueIndex[readers.size()];
 
+            String namedValue = FieldNames.createNamedValue(propertyName, "");
             for (int i = 0; i < readers.size(); i++) {
                 IndexReader r = (IndexReader) readers.get(i);
                 indexes[i] = SharedFieldCache.INSTANCE.getValueIndex(r, field,
-                        FieldNames.createNamedValue(propertyName, ""),
-                        SharedFieldSortComparator.this);
+                        namedValue, SharedFieldSortComparator.this);
             }
         }
 
@@ -317,43 +299,13 @@
                 }
                 InternalValue[] values = state.getValues();
                 if (values.length > 0) {
-                    return getComparable(values[0]);
+                    return Util.getComparable(values[0]);
                 }
                 return null;
             } catch (Exception e) {
                 return null;
             }
         }
-
-        /**
-         * Returns a comparable for the <code>value</code>.
-         *
-         * @param value an internal value.
-         * @return a comparable for the given <code>value</code>.
-         */
-        private Comparable getComparable(InternalValue value) {
-            switch (value.getType()) {
-                case PropertyType.BINARY:
-                    return null;
-                case PropertyType.BOOLEAN:
-                    return ComparableBoolean.valueOf(value.getBoolean());
-                case PropertyType.DATE:
-                    return new Long(value.getDate().getTimeInMillis());
-                case PropertyType.DOUBLE:
-                    return new Double(value.getDouble());
-                case PropertyType.LONG:
-                    return new Long(value.getLong());
-                case PropertyType.NAME:
-                    return value.getQName().toString();
-                case PropertyType.PATH:
-                    return value.getPath().toString();
-                case PropertyType.REFERENCE:
-                case PropertyType.STRING:
-                    return value.getString();
-                default:
-                    return null;
-            }
-        }
     }
 
     /**

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingleColumnQueryResult.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingleColumnQueryResult.java?rev=768954&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingleColumnQueryResult.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SingleColumnQueryResult.java Mon Apr 27 12:43:28 2009
@@ -0,0 +1,76 @@
+/*
+ * 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.lucene;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.ItemManager;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.lucene.search.Query;
+
+/**
+ * <code>SingleColumnQueryResult</code> implements a query result that returns
+ * a single column. That is, executes a lucene query.
+ */
+public class SingleColumnQueryResult extends QueryResultImpl {
+
+    /**
+     * The query to execute.
+     */
+    private final Query query;
+
+    public SingleColumnQueryResult(SearchIndex index,
+                                   ItemManager itemMgr,
+                                   SessionImpl session,
+                                   AccessManager accessMgr,
+                                   AbstractQueryImpl queryImpl,
+                                   Query query,
+                                   SpellSuggestion spellSuggestion,
+                                   Name[] selectProps,
+                                   Path[] orderProps,
+                                   boolean[] orderSpecs,
+                                   boolean documentOrder,
+                                   long offset,
+                                   long limit) throws RepositoryException {
+        super(index, itemMgr, session, accessMgr, queryImpl, spellSuggestion,
+                selectProps, orderProps, orderSpecs, documentOrder, offset, limit);
+        this.query = query;
+        // if document order is requested get all results right away
+        getResults(docOrder ? Integer.MAX_VALUE : index.getResultFetchSize());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected MultiColumnQueryHits executeQuery(long resultFetchHint)
+            throws IOException {
+        return index.executeQuery(session, queryImpl, query,
+                orderProps, orderSpecs, resultFetchHint);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected ExcerptProvider createExcerptProvider() throws IOException {
+        return index.createExcerptProvider(query);
+    }
+}

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

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedLuceneQueryHits.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedLuceneQueryHits.java?rev=768954&r1=768953&r2=768954&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedLuceneQueryHits.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedLuceneQueryHits.java Mon Apr 27 12:43:28 2009
@@ -159,7 +159,7 @@
         for (int i = scoreNodes.size(); i < docs.length; i++) {
             String uuid = reader.document(docs[i].doc).get(FieldNames.UUID);
             NodeId id = new NodeId(UUID.fromString(uuid));
-            scoreNodes.add(new ScoreNode(id, docs[i].score));
+            scoreNodes.add(new ScoreNode(id, docs[i].score, docs[i].doc));
         }
         log.debug("getHits() {}/{}", new Integer(scoreNodes.size()), new Integer(numHits));
         // double hits for next round