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/06/12 12:30:44 UTC

svn commit: r784061 - in /jackrabbit/trunk: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/ jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/query/

Author: mreutegg
Date: Fri Jun 12 10:30:44 2009
New Revision: 784061

URL: http://svn.apache.org/viewvc?rev=784061&view=rev
Log:
JCR-2076: JSR 283: QOM and SQL2
- orderings (work in progress)

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Ordering.java   (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedMultiColumnQueryHits.java   (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FilterMultiColumnQuery.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JoinQuery.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQuery.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryAdapter.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryResult.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java
    jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/query/AbstractOrderByTest.java

Modified: 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=784061&r1=784060&r2=784061&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FilterMultiColumnQuery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/FilterMultiColumnQuery.java Fri Jun 12 10:30:44 2009
@@ -20,7 +20,6 @@
 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;
 
@@ -62,11 +61,11 @@
      * {@inheritDoc}
      */
     public MultiColumnQueryHits execute(final JackrabbitIndexSearcher searcher,
-                                        Sort sort,
+                                        Ordering[] orderings,
                                         long resultFetchHint)
             throws IOException {
-        return new FilterMultiColumnQueryHits(query.execute(
-                searcher, sort, resultFetchHint)) {
+        MultiColumnQueryHits hits = new FilterMultiColumnQueryHits(query.execute(
+                searcher, orderings, resultFetchHint)) {
 
             {
                 log.debug(Arrays.asList(getSelectorNames()).toString());
@@ -95,5 +94,11 @@
                 }
             }
         };
+        if (orderings.length > 0 && hits.getSelectorNames().length > 1) {
+            // subsequent ordering is only needed
+            // when there is more than one column
+            hits = new SortedMultiColumnQueryHits(hits, orderings, searcher.getIndexReader());
+        }
+        return hits;
     }
 }

Modified: 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=784061&r1=784060&r2=784061&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JoinQuery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/JoinQuery.java Fri Jun 12 10:30:44 2009
@@ -18,7 +18,6 @@
 
 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;
@@ -89,13 +88,13 @@
      * {@inheritDoc}
      */
     public MultiColumnQueryHits execute(JackrabbitIndexSearcher searcher,
-                                        Sort sort,
+                                        Ordering[] orderings,
                                         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),
+        return Join.create(left.execute(searcher, orderings, resultFetchHint),
+                right.execute(searcher, orderings, resultFetchHint),
                 joinType, joinCondition, reader, resolver, scs, hmgr);
     }
 }

Modified: 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=784061&r1=784060&r2=784061&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQuery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQuery.java Fri Jun 12 10:30:44 2009
@@ -18,8 +18,6 @@
 
 import java.io.IOException;
 
-import org.apache.lucene.search.Sort;
-
 /**
  * <code>MultiColumnQuery</code> defines an interface for a query that returns
  * {@link MultiColumnQueryHits}.
@@ -30,13 +28,13 @@
      * Executes this query and returns multi column query hits.
      *
      * @param searcher        the index searcher.
-     * @param sort            the sort criteria.
+     * @param orderings       the orderings.
      * @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,
+                                        Ordering[] orderings,
                                         long resultFetchHint)
             throws IOException;
 }

Modified: 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=784061&r1=784060&r2=784061&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryAdapter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryAdapter.java Fri Jun 12 10:30:44 2009
@@ -19,6 +19,7 @@
 import java.io.IOException;
 
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
 import org.apache.lucene.search.Sort;
 import org.apache.jackrabbit.spi.Name;
 
@@ -64,9 +65,13 @@
      * {@inheritDoc}
      */
     public MultiColumnQueryHits execute(JackrabbitIndexSearcher searcher,
-                                        Sort sort,
+                                        Ordering[] orderings,
                                         long resultFetchHint)
             throws IOException {
-        return searcher.execute(query, sort, resultFetchHint, selectorName);
+        SortField[] fields = new SortField[orderings.length];
+        for (int i = 0; i < orderings.length; i++) {
+            fields[i] = orderings[i].getSortField();
+        }
+        return searcher.execute(query, new Sort(fields), resultFetchHint, selectorName);
     }
 }

Modified: 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=784061&r1=784060&r2=784061&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryResult.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/MultiColumnQueryResult.java Fri Jun 12 10:30:44 2009
@@ -40,7 +40,7 @@
     /**
      * The order specifier for each of the order properties.
      */
-    protected final OrderingImpl[] orderings;
+    protected final Ordering[] orderings;
 
     public MultiColumnQueryResult(SearchIndex index,
                                   ItemManager itemMgr,
@@ -57,7 +57,7 @@
         super(index, itemMgr, session, accessMgr, queryImpl, spellSuggestion,
                 columns, documentOrder, offset, limit);
         this.query = query;
-        this.orderings = orderings;
+        this.orderings = index.createOrderings(orderings);
         // if document order is requested get all results right away
         getResults(docOrder ? Integer.MAX_VALUE : index.getResultFetchSize());
     }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Ordering.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Ordering.java?rev=784061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Ordering.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/Ordering.java Fri Jun 12 10:30:44 2009
@@ -0,0 +1,157 @@
+/*
+ * 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.jackrabbit.spi.commons.query.qom.OrderingImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.QOMTreeVisitor;
+import org.apache.jackrabbit.spi.commons.query.qom.DefaultTraversingQOMTreeVisitor;
+import org.apache.jackrabbit.spi.commons.query.qom.LengthImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.PropertyValueImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.LowerCaseImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.DynamicOperandImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.UpperCaseImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.FullTextSearchScoreImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.NodeLocalNameImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.NodeNameImpl;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.SortComparatorSource;
+
+/**
+ * <code>Ordering</code> implements a single ordering specification.
+ */
+public class Ordering {
+
+    /**
+     * The selector name where this ordering applies to.
+     */
+    private final Name selectorName;
+
+    /**
+     * The lucene sort field for this ordering.
+     */
+    private final SortField sort;
+
+    /**
+     * Private constructor.
+     *
+     * @param selectorName the selector name for this ordering.
+     * @param sort         the lucene sort field for this ordering.
+     */
+    private Ordering(Name selectorName, SortField sort) {
+        this.selectorName = selectorName;
+        this.sort = sort;
+    }
+
+    /**
+     * @return the selector name where this ordering applies to.
+     */
+    public Name getSelectorName() {
+        return selectorName;
+    }
+
+    /**
+     * @return the lucene sort field for this ordering.
+     */
+    public SortField getSortField() {
+        return sort;
+    }
+
+    /**
+     * Creates an ordering from a JCR QOM ordering.
+     *
+     * @param ordering   the JCR QOM ordering specification.
+     * @param scs        the sort comparator source from the search index.
+     * @param nsMappings the index internal namespace mappings.
+     * @return an ordering.
+     * @throws RepositoryException if an error occurs while translating the JCR
+     *                             QOM ordering.
+     */
+    public static Ordering fromQOM(final OrderingImpl ordering,
+                                    final SortComparatorSource scs,
+                                    final NamespaceMappings nsMappings)
+            throws RepositoryException {
+        final Name[] selectorName = new Name[1];
+        QOMTreeVisitor visitor = new DefaultTraversingQOMTreeVisitor() {
+
+            public Object visit(LengthImpl node, Object data) throws Exception {
+                PropertyValueImpl propValue = (PropertyValueImpl) node.getPropertyValue();
+                selectorName[0] = propValue.getSelectorQName();
+                return new SortField(propValue.getPropertyQName().toString(),
+                        new LengthSortComparator(nsMappings),
+                        !ordering.isAscending());
+            }
+
+            public Object visit(LowerCaseImpl node, Object data)
+                    throws Exception {
+                SortField sf = (SortField) ((DynamicOperandImpl) node.getOperand()).accept(this, data);
+                selectorName[0] = node.getSelectorQName();
+                return new SortField(sf.getField(),
+                        new LowerCaseSortComparator(sf.getFactory()),
+                        !ordering.isAscending());
+            }
+
+            public Object visit(UpperCaseImpl node, Object data)
+                    throws Exception {
+                SortField sf = (SortField) ((DynamicOperandImpl) node.getOperand()).accept(this, data);
+                selectorName[0] = node.getSelectorQName();
+                return new SortField(sf.getField(),
+                        new UpperCaseSortComparator(sf.getFactory()),
+                        !ordering.isAscending());
+            }
+
+            public Object visit(FullTextSearchScoreImpl node, Object data)
+                    throws Exception {
+                selectorName[0] = node.getSelectorQName();
+                return new SortField(null, SortField.SCORE,
+                        ordering.isAscending());
+            }
+
+            public Object visit(NodeLocalNameImpl node, Object data) throws Exception {
+                selectorName[0] = node.getSelectorQName();
+                return new SortField(FieldNames.LOCAL_NAME,
+                       SortField.STRING, !ordering.isAscending());
+            }
+
+            public Object visit(NodeNameImpl node, Object data) throws Exception {
+                selectorName[0] = node.getSelectorQName();
+                return new SortField(FieldNames.LABEL,
+                       SortField.STRING, !ordering.isAscending());
+            }
+
+            public Object visit(PropertyValueImpl node, Object data)
+                    throws Exception {
+                selectorName[0] = node.getSelectorQName();
+                return new SortField(node.getPropertyQName().toString(),
+                        scs, !ordering.isAscending());
+            }
+
+            public Object visit(OrderingImpl node, Object data)
+                    throws Exception {
+                return ((DynamicOperandImpl) node.getOperand()).accept(this, data);
+            }
+        };
+        try {
+            SortField field = (SortField) ordering.accept(visitor, null);
+            return new Ordering(selectorName[0], field);
+        } catch (Exception e) {
+            throw new RepositoryException(e);
+        }
+    }
+}

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

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=784061&r1=784060&r2=784061&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 Fri Jun 12 10:30:44 2009
@@ -46,16 +46,6 @@
 import org.apache.jackrabbit.spi.commons.query.DefaultQueryNodeFactory;
 import org.apache.jackrabbit.spi.commons.query.qom.QueryObjectModelTree;
 import org.apache.jackrabbit.spi.commons.query.qom.OrderingImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.QOMTreeVisitor;
-import org.apache.jackrabbit.spi.commons.query.qom.DefaultTraversingQOMTreeVisitor;
-import org.apache.jackrabbit.spi.commons.query.qom.LengthImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.LowerCaseImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.UpperCaseImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.FullTextSearchScoreImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.NodeLocalNameImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.NodeNameImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.PropertyValueImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.DynamicOperandImpl;
 import org.apache.jackrabbit.uuid.UUID;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -791,19 +781,17 @@
      */
     public MultiColumnQueryHits executeQuery(SessionImpl session,
                                              MultiColumnQuery query,
-                                             OrderingImpl[] orderings,
+                                             Ordering[] orderings,
                                              long resultFetchHint)
             throws IOException {
         checkOpen();
 
-        Sort sort = new Sort(createSortFields(orderings));
-
         final IndexReader reader = getIndexReader();
         JackrabbitIndexSearcher searcher = new JackrabbitIndexSearcher(
                 session, reader, getContext().getItemStateManager());
         searcher.setSimilarity(getSimilarity());
         return new FilterMultiColumnQueryHits(
-                query.execute(searcher, sort, resultFetchHint)) {
+                query.execute(searcher, orderings, resultFetchHint)) {
             public void close() throws IOException {
                 try {
                     super.close();
@@ -998,74 +986,19 @@
     }
 
     /**
-     * Creates sort fields for the ordering specifications.
+     * Creates internal orderings for the QOM ordering specifications.
      *
-     * @param orderings the ordering specifications.
-     * @return the sort fields.
+     * @param orderings the QOM ordering specifications.
+     * @return the internal orderings.
+     * @throws RepositoryException if an error occurs.
      */
-    protected SortField[] createSortFields(OrderingImpl[] orderings) {
-        List<SortField> sortFields = new ArrayList<SortField>();
-        for (final OrderingImpl ordering : orderings) {
-            QOMTreeVisitor visitor = new DefaultTraversingQOMTreeVisitor() {
-
-                public Object visit(LengthImpl node, Object data) throws Exception {
-                    PropertyValueImpl propValue = (PropertyValueImpl) node.getPropertyValue();
-                    return new SortField(propValue.getPropertyQName().toString(),
-                            new LengthSortComparator(nsMappings),
-                            !ordering.isAscending());
-                }
-
-                public Object visit(LowerCaseImpl node, Object data)
-                        throws Exception {
-                    SortField sf = (SortField) ((DynamicOperandImpl) node.getOperand()).accept(this, data);
-                    return new SortField(sf.getField(),
-                            new LowerCaseSortComparator(sf.getFactory()),
-                            !ordering.isAscending());
-                }
-
-                public Object visit(UpperCaseImpl node, Object data)
-                        throws Exception {
-                    SortField sf = (SortField) ((DynamicOperandImpl) node.getOperand()).accept(this, data);
-                    return new SortField(sf.getField(),
-                            new UpperCaseSortComparator(sf.getFactory()),
-                            !ordering.isAscending());
-                }
-
-                public Object visit(FullTextSearchScoreImpl node, Object data)
-                        throws Exception {
-                    // TODO: selector ignored
-                    return new SortField(null, SortField.SCORE,
-                            ordering.isAscending());
-                }
-
-                public Object visit(NodeLocalNameImpl node, Object data) throws Exception {
-                    return new SortField(FieldNames.LOCAL_NAME,
-                           SortField.STRING, !ordering.isAscending());
-                }
-
-                public Object visit(NodeNameImpl node, Object data) throws Exception {
-                    return new SortField(FieldNames.LABEL,
-                           SortField.STRING, !ordering.isAscending());
-                }
-
-                public Object visit(PropertyValueImpl node, Object data)
-                        throws Exception {
-                    return new SortField(node.getPropertyQName().toString(),
-                            scs, !ordering.isAscending());
-                }
-
-                public Object visit(OrderingImpl node, Object data)
-                        throws Exception {
-                    return ((DynamicOperandImpl) node.getOperand()).accept(this, data);
-                }
-            };
-            try {
-                sortFields.add((SortField) ordering.accept(visitor, null));
-            } catch (Exception e) {
-                // TODO
-            }
+    protected Ordering[] createOrderings(OrderingImpl[] orderings)
+            throws RepositoryException {
+        Ordering[] ords = new Ordering[orderings.length];
+        for (int i = 0; i < orderings.length; i++) {
+            ords[i] = Ordering.fromQOM(orderings[i], scs, nsMappings);
         }
-        return sortFields.toArray(new SortField[sortFields.size()]);
+        return ords;
     }
 
     /**

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedMultiColumnQueryHits.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedMultiColumnQueryHits.java?rev=784061&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedMultiColumnQueryHits.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/SortedMultiColumnQueryHits.java Fri Jun 12 10:30:44 2009
@@ -0,0 +1,202 @@
+/*
+ * 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.List;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.ScoreDocComparator;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.jackrabbit.spi.Name;
+
+/**
+ * <code>SortedMultiColumnQueryHits</code> implements sorting of query hits
+ * based on {@link Ordering}s.
+ */
+public class SortedMultiColumnQueryHits extends FilterMultiColumnQueryHits {
+
+    /**
+     * Iterator over sorted ScoreNode[]s.
+     */
+    private final Iterator<ScoreNode[]> it;
+
+    /**
+     * Creates sorted query hits.
+     *
+     * @param hits      the hits to sort.
+     * @param orderings the ordering specifications.
+     * @param reader    the current index reader.
+     * @throws IOException if an error occurs while reading from the index.
+     */
+    public SortedMultiColumnQueryHits(MultiColumnQueryHits hits,
+                                      Ordering[] orderings,
+                                      IndexReader reader)
+            throws IOException {
+        super(hits);
+        List<ScoreNode[]> sortedHits = new ArrayList<ScoreNode[]>();
+        ScoreNode[] next;
+        while ((next = hits.nextScoreNodes()) != null) {
+            sortedHits.add(next);
+        }
+        try {
+            Collections.sort(sortedHits, new ScoreNodeComparator(
+                    reader, orderings, hits.getSelectorNames()));
+        } catch (RuntimeException e) {
+            // might be thrown by ScoreNodeComparator#compare
+            throw Util.createIOException(e);
+        }
+        this.it = sortedHits.iterator();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ScoreNode[] nextScoreNodes() throws IOException {
+        if (it.hasNext()) {
+            return it.next();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void skip(int n) throws IOException {
+        while (n-- > 0) {
+            nextScoreNodes();
+        }
+    }
+
+    /**
+     * A comparator that compares ScoreNode[].
+     */
+    private static final class ScoreNodeComparator
+            implements Comparator<ScoreNode[]> {
+
+        /**
+         * The current index reader.
+         */
+        private final IndexReader reader;
+
+        /**
+         * The ordering specifications.
+         */
+        private final Ordering[] orderings;
+
+        /**
+         * The selector name index for each of the {@link #orderings}.
+         */
+        private final int[] idx;
+
+        /**
+         * The score doc comparator for each of the {@link #orderings}.
+         */
+        private final ScoreDocComparator[] comparators;
+
+        /**
+         * The reverse flag for each of the {@link #orderings}.
+         */
+        private final boolean[] isReverse;
+
+        /**
+         * Reusable ScoreDoc for use in {@link #compare(ScoreNode[], ScoreNode[])}.
+         */
+        private final ScoreDoc doc1 = new ScoreDoc(0, 1.0f);
+
+        /**
+         * Reusable ScoreDoc for use in {@link #compare(ScoreNode[], ScoreNode[])}.
+         */
+        private final ScoreDoc doc2 = new ScoreDoc(0, 1.0f);
+
+        /**
+         * Creates a new comparator.
+         *
+         * @param reader        the current index reader.
+         * @param orderings     the ordering specifications.
+         * @param selectorNames the selector names associated with the
+         *                      ScoreNode[] used in
+         *                      {@link #compare(ScoreNode[], ScoreNode[])}.
+         * @throws IOException if an error occurs while reading from the index.
+         */
+        private ScoreNodeComparator(IndexReader reader,
+                                    Ordering[] orderings,
+                                    Name[] selectorNames)
+                throws IOException {
+            this.reader = reader;
+            this.orderings = orderings;
+            List names = Arrays.asList(selectorNames);
+            this.idx = new int[orderings.length];
+            this.comparators = new ScoreDocComparator[orderings.length];
+            this.isReverse = new boolean[orderings.length];
+            for (int i = 0; i < orderings.length; i++) {
+                idx[i] = names.indexOf(orderings[i].getSelectorName());
+                SortField sf = orderings[i].getSortField();
+                if (sf.getFactory() != null) {
+                    comparators[i] = sf.getFactory().newComparator(reader, sf.getField());
+                }
+                isReverse[i] = sf.getReverse();
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public int compare(ScoreNode[] sn1, ScoreNode[] sn2) {
+            for (int i = 0; i < orderings.length; i++) {
+                int c;
+                int scoreNodeIndex = idx[i];
+                ScoreNode n1 = sn1[scoreNodeIndex];
+                ScoreNode n2 = sn2[scoreNodeIndex];
+                if (n1 == n2) {
+                    continue;
+                } else if (n1 == null) {
+                    c = -1;
+                } else if (n2 == null) {
+                    c = 1;
+                } else if (comparators[i] != null) {
+                    try {
+                        doc1.doc = n1.getDoc(reader);
+                        doc1.score = n1.getScore();
+                        doc2.doc = n2.getDoc(reader);
+                        doc2.score = n2.getScore();
+                    } catch (IOException e) {
+                        throw new RuntimeException(e.getMessage(), e);
+                    }
+                    c = comparators[i].compare(doc1, doc2);
+                } else {
+                    // compare score
+                    c = new Float(n1.getScore()).compareTo(n2.getScore());
+                }
+                if (c != 0) {
+                    if (isReverse[i]) {
+                        c = -c;
+                    }
+                    return c;
+                }
+            }
+            return 0;
+        }
+    }
+}

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

Modified: jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/query/AbstractOrderByTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/query/AbstractOrderByTest.java?rev=784061&r1=784060&r2=784061&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/query/AbstractOrderByTest.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr-tests/src/main/java/org/apache/jackrabbit/test/api/query/AbstractOrderByTest.java Fri Jun 12 10:30:44 2009
@@ -20,12 +20,10 @@
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
 import javax.jcr.Repository;
-import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryResult;
 import javax.jcr.query.qom.QueryObjectModel;
-import javax.jcr.query.qom.QueryObjectModelFactory;
 import javax.jcr.query.qom.Ordering;
 import javax.jcr.query.qom.DynamicOperand;