Index: src/main/java/org/apache/jackrabbit/core/query/lucene/DocOrderNodeIteratorImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/DocOrderNodeIteratorImpl.java (revision 755749) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/DocOrderNodeIteratorImpl.java (working copy) @@ -1,297 +0,0 @@ -/* - * 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 org.apache.jackrabbit.core.ItemManager; -import org.apache.jackrabbit.core.NodeImpl; -import org.apache.jackrabbit.spi.Path; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.RepositoryException; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; -import java.util.ArrayList; - -/** - * Implements a NodeIterator that returns the nodes in document order. - */ -class DocOrderNodeIteratorImpl implements ScoreNodeIterator { - - /** Logger instance for this class */ - private static final Logger log = LoggerFactory.getLogger(DocOrderNodeIteratorImpl.class); - - /** A node iterator with ordered nodes */ - private NodeIteratorImpl orderedNodes; - - /** Unordered list of {@link ScoreNode}[]s. */ - private final List scoreNodes; - - /** ItemManager to turn UUIDs into Node instances */ - protected final ItemManager itemMgr; - - /** - * Apply document order on the score nodes with this selectorIndex. - */ - private final int selectorIndex; - - /** - * Creates a DocOrderNodeIteratorImpl that orders the nodes in - * scoreNodes in document order. - * - * @param itemMgr the item manager of the session executing the - * query. - * @param scoreNodes the ids of the matching nodes with their score - * value. List<ScoreNode[]> - * @param selectorIndex apply document order on the score nodes with this - * selectorIndex. - */ - DocOrderNodeIteratorImpl(ItemManager itemMgr, - List scoreNodes, - int selectorIndex) { - this.itemMgr = itemMgr; - this.scoreNodes = scoreNodes; - this.selectorIndex = selectorIndex; - } - - /** - * {@inheritDoc} - */ - public Object next() { - return nextNodeImpl(); - } - - /** - * {@inheritDoc} - */ - public Node nextNode() { - return nextNodeImpl(); - } - - /** - * {@inheritDoc} - */ - public NodeImpl nextNodeImpl() { - initOrderedIterator(); - return orderedNodes.nextNodeImpl(); - } - - /** - * @throws UnsupportedOperationException always. - */ - public void remove() { - throw new UnsupportedOperationException("remove"); - } - - /** - * {@inheritDoc} - */ - public void skip(long skipNum) { - initOrderedIterator(); - orderedNodes.skip(skipNum); - } - - /** - * Returns the number of nodes in this iterator. - *

- * Note: The number returned by this method may differ from the number - * of nodes actually returned by calls to hasNext() / getNextNode()! This - * is because this iterator works on a lazy instantiation basis and while - * iterating over the nodes some of them might have been deleted in the - * meantime. Those will not be returned by getNextNode(). As soon as an - * invalid node is detected, the size of this iterator is adjusted. - * - * @return the number of node in this iterator. - */ - public long getSize() { - if (orderedNodes != null) { - return orderedNodes.getSize(); - } else { - return scoreNodes.size(); - } - } - - /** - * {@inheritDoc} - */ - public long getPosition() { - initOrderedIterator(); - return orderedNodes.getPosition(); - } - - /** - * {@inheritDoc} - */ - public boolean hasNext() { - initOrderedIterator(); - return orderedNodes.hasNext(); - } - - /** - * {@inheritDoc} - */ - public float getScore() { - initOrderedIterator(); - return orderedNodes.getScore(); - } - - /** - * {@inheritDoc} - */ - public ScoreNode[] getScoreNodes() { - initOrderedIterator(); - return orderedNodes.getScoreNodes(); - } - - //------------------------< internal >-------------------------------------- - - /** - * Initializes the NodeIterator in document order - */ - private void initOrderedIterator() { - if (orderedNodes != null) { - return; - } - long time = System.currentTimeMillis(); - ScoreNode[][] nodes = (ScoreNode[][]) scoreNodes.toArray(new ScoreNode[scoreNodes.size()][]); - - final List invalidIDs = new ArrayList(2); - - do { - if (invalidIDs.size() > 0) { - // previous sort run was not successful -> remove failed uuids - List tmp = new ArrayList(); - for (int i = 0; i < nodes.length; i++) { - if (!invalidIDs.contains(nodes[i][selectorIndex].getNodeId())) { - tmp.add(nodes[i]); - } - } - nodes = (ScoreNode[][]) tmp.toArray(new ScoreNode[tmp.size()][]); - invalidIDs.clear(); - } - - try { - // sort the uuids - Arrays.sort(nodes, new Comparator() { - public int compare(Object o1, Object o2) { - ScoreNode n1 = ((ScoreNode[]) o1)[selectorIndex]; - ScoreNode n2 = ((ScoreNode[]) o2)[selectorIndex]; - // handle null values - // null is considered less than any value - if (n1 == n2) { - return 0; - } else if (n1 == null) { - return -1; - } else if (n2 == null) { - return 1; - } - try { - NodeImpl node1; - try { - node1 = (NodeImpl) itemMgr.getItem(n1.getNodeId()); - } catch (RepositoryException e) { - log.warn("Node " + n1.getNodeId() + " does not exist anymore: " + e); - // node does not exist anymore - invalidIDs.add(n1.getNodeId()); - SortFailedException sfe = new SortFailedException(); - sfe.initCause(e); - throw sfe; - } - NodeImpl node2; - try { - node2 = (NodeImpl) itemMgr.getItem(n2.getNodeId()); - } catch (RepositoryException e) { - log.warn("Node " + n2.getNodeId() + " does not exist anymore: " + e); - // node does not exist anymore - invalidIDs.add(n2.getNodeId()); - SortFailedException sfe = new SortFailedException(); - sfe.initCause(e); - throw sfe; - } - Path.Element[] path1 = node1.getPrimaryPath().getElements(); - Path.Element[] path2 = node2.getPrimaryPath().getElements(); - - // find nearest common ancestor - int commonDepth = 0; // root - while (path1.length > commonDepth && path2.length > commonDepth) { - if (path1[commonDepth].equals(path2[commonDepth])) { - commonDepth++; - } else { - break; - } - } - // path elements at last depth were equal - commonDepth--; - - // check if either path is an ancestor of the other - if (path1.length - 1 == commonDepth) { - // path1 itself is ancestor of path2 - return -1; - } - if (path2.length - 1 == commonDepth) { - // path2 itself is ancestor of path1 - return 1; - } - // get common ancestor node - NodeImpl commonNode = (NodeImpl) node1.getAncestor(commonDepth); - // move node1/node2 to the commonDepth + 1 - // node1 and node2 then will be child nodes of commonNode - node1 = (NodeImpl) node1.getAncestor(commonDepth + 1); - node2 = (NodeImpl) node2.getAncestor(commonDepth + 1); - for (NodeIterator it = commonNode.getNodes(); it.hasNext();) { - Node child = it.nextNode(); - if (child.isSame(node1)) { - return -1; - } else if (child.isSame(node2)) { - return 1; - } - } - log.error("Internal error: unable to determine document order of nodes:"); - log.error("\tNode1: " + node1.getPath()); - log.error("\tNode2: " + node2.getPath()); - } catch (RepositoryException e) { - log.error("Exception while sorting nodes in document order: " + e.toString(), e); - } - // if we get here something went wrong - // remove both uuids from array - invalidIDs.add(n1.getNodeId()); - invalidIDs.add(n2.getNodeId()); - // terminate sorting - throw new SortFailedException(); - } - }); - } catch (SortFailedException e) { - // retry - } - - } while (invalidIDs.size() > 0); - - if (log.isDebugEnabled()) { - log.debug("" + nodes.length + " node(s) ordered in " + (System.currentTimeMillis() - time) + " ms"); - } - orderedNodes = new NodeIteratorImpl(itemMgr, nodes, selectorIndex); - } - - /** - * Indicates that sorting failed. - */ - private static final class SortFailedException extends RuntimeException { - } -} Index: src/main/java/org/apache/jackrabbit/core/query/lucene/DocOrderScoreNodeIterator.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/DocOrderScoreNodeIterator.java (revision 746932) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/DocOrderScoreNodeIterator.java (working copy) @@ -31,15 +31,15 @@ import java.util.ArrayList; /** - * Implements a NodeIterator that returns the nodes in document order. + * Implements a ScoreNodeIterator that returns the score nodes in document order. */ -class DocOrderNodeIteratorImpl implements ScoreNodeIterator { +class DocOrderScoreNodeIterator implements ScoreNodeIterator { /** Logger instance for this class */ - private static final Logger log = LoggerFactory.getLogger(DocOrderNodeIteratorImpl.class); + private static final Logger log = LoggerFactory.getLogger(DocOrderScoreNodeIterator.class); /** A node iterator with ordered nodes */ - private NodeIteratorImpl orderedNodes; + private ScoreNodeIterator orderedNodes; /** Unordered list of {@link ScoreNode}[]s. */ private final List scoreNodes; @@ -53,7 +53,7 @@ private final int selectorIndex; /** - * Creates a DocOrderNodeIteratorImpl that orders the nodes in + * Creates a DocOrderScoreNodeIterator that orders the nodes in * scoreNodes in document order. * * @param itemMgr the item manager of the session executing the @@ -63,7 +63,7 @@ * @param selectorIndex apply document order on the score nodes with this * selectorIndex. */ - DocOrderNodeIteratorImpl(ItemManager itemMgr, + DocOrderScoreNodeIterator(ItemManager itemMgr, List scoreNodes, int selectorIndex) { this.itemMgr = itemMgr; @@ -75,22 +75,15 @@ * {@inheritDoc} */ public Object next() { - return nextNodeImpl(); + return nextScoreNodes(); } /** * {@inheritDoc} */ - public Node nextNode() { - return nextNodeImpl(); - } - - /** - * {@inheritDoc} - */ - public NodeImpl nextNodeImpl() { + public ScoreNode[] nextScoreNodes() { initOrderedIterator(); - return orderedNodes.nextNodeImpl(); + return orderedNodes.nextScoreNodes(); } /** @@ -144,22 +137,6 @@ return orderedNodes.hasNext(); } - /** - * {@inheritDoc} - */ - public float getScore() { - initOrderedIterator(); - return orderedNodes.getScore(); - } - - /** - * {@inheritDoc} - */ - public ScoreNode[] getScoreNodes() { - initOrderedIterator(); - return orderedNodes.getScoreNodes(); - } - //------------------------< internal >-------------------------------------- /** @@ -286,7 +263,7 @@ if (log.isDebugEnabled()) { log.debug("" + nodes.length + " node(s) ordered in " + (System.currentTimeMillis() - time) + " ms"); } - orderedNodes = new NodeIteratorImpl(itemMgr, nodes, selectorIndex); + orderedNodes = new ScoreNodeIteratorImpl(nodes); } /** Property changes on: src\main\java\org\apache\jackrabbit\core\query\lucene\DocOrderScoreNodeIterator.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIteratorImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIteratorImpl.java (revision 755749) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIteratorImpl.java (working copy) @@ -23,19 +23,21 @@ import javax.jcr.Node; import javax.jcr.RepositoryException; +import javax.jcr.NodeIterator; + import java.util.NoSuchElementException; /** * Implements a {@link javax.jcr.NodeIterator} returned by * {@link javax.jcr.query.QueryResult#getNodes()}. */ -class NodeIteratorImpl implements ScoreNodeIterator { +class NodeIteratorImpl implements NodeIterator { /** Logger instance for this class */ private static final Logger log = LoggerFactory.getLogger(NodeIteratorImpl.class); /** The node ids of the nodes in the result set with their score value */ - protected final ScoreNode[][] scoreNodes; + protected final ScoreNodeIterator scoreNodes; /** The index for the default selector withing {@link #scoreNodes} */ private final int selectorIndex; @@ -43,9 +45,6 @@ /** ItemManager to turn UUIDs into Node instances */ protected final ItemManager itemMgr; - /** Current position in the UUID array */ - protected int pos = -1; - /** Number of invalid nodes */ protected int invalid = 0; @@ -57,12 +56,12 @@ * * @param itemMgr the ItemManager to turn UUIDs into * Node instances. - * @param scoreNodes the node ids of the matching nodes. + * @param scoreNodes iterator over score nodes. * @param selectorIndex the index for the default selector within * scoreNodes. */ NodeIteratorImpl(ItemManager itemMgr, - ScoreNode[][] scoreNodes, + ScoreNodeIterator scoreNodes, int selectorIndex) { this.itemMgr = itemMgr; this.scoreNodes = scoreNodes; @@ -77,7 +76,12 @@ * Nodes. */ public Node nextNode() throws NoSuchElementException { - return nextNodeImpl(); + if (next == null) { + throw new NoSuchElementException(); + } + NodeImpl n = next; + fetchNext(); + return n; } /** @@ -91,37 +95,14 @@ } /** - * Returns the next Node in the result set. - * - * @return the next Node in the result set. - * @throws NoSuchElementException if iteration has no more Nodes. - */ - public NodeImpl nextNodeImpl() throws NoSuchElementException { - if (next == null) { - throw new NoSuchElementException(); - } - NodeImpl n = next; - fetchNext(); - return n; - } - - /** * Skip a number of Nodes in this iterator. * @param skipNum the non-negative number of Nodes to skip * @throws NoSuchElementException * if skipped past the last Node in this iterator. */ public void skip(long skipNum) throws NoSuchElementException { - if (skipNum < 0) { - throw new IllegalArgumentException("skipNum must not be negative"); - } - if ((pos + skipNum) > scoreNodes.length) { - throw new NoSuchElementException(); - } - if (skipNum == 0) { - // do nothing - } else { - pos += skipNum - 1; + if (skipNum > 0) { + scoreNodes.skip(skipNum - 1); fetchNext(); } } @@ -139,7 +120,12 @@ * @return the number of node in this iterator. */ public long getSize() { - return scoreNodes.length - invalid; + long size = scoreNodes.getSize(); + if (size == -1) { + return size; + } else { + return size - invalid; + } } /** @@ -147,7 +133,13 @@ * @return the current position in this NodeIterator. */ public long getPosition() { - return pos - invalid; + long position = scoreNodes.getPosition() - invalid; + // scoreNode.getPosition() is one ahead + // if there is a prefetched node + if (next != null) { + position--; + } + return position; } /** @@ -168,26 +160,6 @@ } /** - * Returns the score of the node returned by {@link #nextNode()}. In other - * words, this method returns the score value of the next Node. - * @return the score of the node returned by {@link #nextNode()}. - * @throws NoSuchElementException if there is no next node. - */ - public float getScore() throws NoSuchElementException { - if (!hasNext()) { - throw new NoSuchElementException(); - } - return scoreNodes[pos][selectorIndex].getScore(); - } - - /** - * {@inheritDoc} - */ - public ScoreNode[] getScoreNodes() { - return scoreNodes[pos]; - } - - /** * Clears {@link #next} and tries to fetch the next Node instance. * When this method returns {@link #next} refers to the next available * node instance in this iterator. If {@link #next} is null when this @@ -196,17 +168,16 @@ protected void fetchNext() { // reset next = null; - while (next == null && (pos + 1) < scoreNodes.length) { + while (next == null && scoreNodes.hasNext()) { + ScoreNode[] sn = scoreNodes.nextScoreNodes(); try { - next = (NodeImpl) itemMgr.getItem(scoreNodes[pos + 1][selectorIndex].getNodeId()); + next = (NodeImpl) itemMgr.getItem(sn[selectorIndex].getNodeId()); } catch (RepositoryException e) { log.warn("Exception retrieving Node with UUID: " - + scoreNodes[pos + 1][selectorIndex].getNodeId() + ": " + e.toString()); + + sn[selectorIndex].getNodeId() + ": " + e.toString()); // try next invalid++; - pos++; } } - pos++; } } Index: src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java (revision 755749) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/QueryResultImpl.java (working copy) @@ -17,7 +17,6 @@ package org.apache.jackrabbit.core.query.lucene; import org.apache.jackrabbit.core.ItemManager; -import org.apache.jackrabbit.core.NodeImpl; import org.apache.jackrabbit.core.SessionImpl; import org.apache.jackrabbit.core.security.AccessManager; import org.apache.jackrabbit.spi.Name; @@ -28,7 +27,6 @@ import javax.jcr.ItemNotFoundException; import javax.jcr.NamespaceException; -import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.query.QueryResult; @@ -161,6 +159,8 @@ * document order. * @param limit the maximum result size * @param offset the offset in the total result set + * @throws RepositoryException if an error occurs while reading from the + * repository. */ public QueryResultImpl(SearchIndex index, ItemManager itemMgr, @@ -213,7 +213,7 @@ * {@inheritDoc} */ public NodeIterator getNodes() throws RepositoryException { - return getNodeIterator(); + return new NodeIteratorImpl(itemMgr, getScoreNodes(), 0); } /** @@ -227,8 +227,9 @@ throw new RepositoryException(e); } } - return new RowIteratorImpl(getNodeIterator(), selectProps, - queryImpl.getSelectorNames(), itemMgr, session, + return new RowIteratorImpl(getScoreNodes(), selectProps, + queryImpl.getSelectorNames(), itemMgr, + index.getContext().getHierarchyManager(), session, excerptProvider, spellSuggestion); } @@ -247,15 +248,15 @@ //--------------------------------< internal >------------------------------ /** - * Creates a node iterator over the result nodes. + * Creates a {@link ScoreNodeIterator} over the query result. * - * @return a node iterator over the result nodes. + * @return a {@link ScoreNodeIterator} over the query result. */ - private ScoreNodeIterator getNodeIterator() { + private ScoreNodeIterator getScoreNodes() { if (docOrder) { - return new DocOrderNodeIteratorImpl(itemMgr, resultNodes, 0); + return new DocOrderScoreNodeIterator(itemMgr, resultNodes, 0); } else { - return new LazyScoreNodeIterator(0); + return new LazyScoreNodeIteratorImpl(); } } @@ -383,6 +384,8 @@ * number may get smaller if nodes are found in the result set which the * current session has no permission to access. This method may return * -1 if the total size is unknown. + * + * @return the total number of hits. */ public int getTotalSize() { if (numResults == -1) { @@ -392,65 +395,27 @@ } } - private final class LazyScoreNodeIterator implements ScoreNodeIterator { + private final class LazyScoreNodeIteratorImpl implements ScoreNodeIterator { private int position = -1; private boolean initialized = false; - private NodeImpl next; + private ScoreNode[] next; - private final int selectorIndex; - - private LazyScoreNodeIterator(int selectorIndex) { - this.selectorIndex = selectorIndex; - } - - /** - * {@inheritDoc} - */ - public float getScore() { + public ScoreNode[] nextScoreNodes() { initialize(); - if (!hasNext()) { - throw new NoSuchElementException(); - } - return ((ScoreNode[]) resultNodes.get(position))[selectorIndex].getScore(); - } - - /** - * {@inheritDoc} - */ - public ScoreNode[] getScoreNodes() { - initialize(); - if (!hasNext()) { - throw new NoSuchElementException(); - } - return (ScoreNode[]) resultNodes.get(position); - } - - /** - * {@inheritDoc} - */ - public NodeImpl nextNodeImpl() { - initialize(); if (next == null) { throw new NoSuchElementException(); } - NodeImpl n = next; + ScoreNode[] sn = next; fetchNext(); - return n; + return sn; } /** * {@inheritDoc} */ - public Node nextNode() { - return nextNodeImpl(); - } - - /** - * {@inheritDoc} - */ public void skip(long skipNum) { initialize(); if (skipNum < 0) { @@ -522,7 +487,7 @@ * {@inheritDoc} */ public Object next() { - return nextNodeImpl(); + return nextScoreNodes(); } /** @@ -569,16 +534,7 @@ break; } } - ScoreNode[] sn = (ScoreNode[]) resultNodes.get(nextPos); - try { - next = (NodeImpl) itemMgr.getItem(sn[selectorIndex].getNodeId()); - } catch (RepositoryException e) { - log.warn("Exception retrieving Node with UUID: " - + sn[selectorIndex].getNodeId() + ": " + e.toString()); - // remove score node and try next - resultNodes.remove(nextPos); - invalid++; - } + next = (ScoreNode[]) resultNodes.get(nextPos); } position++; } Index: src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java (revision 755749) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/RowIteratorImpl.java (working copy) @@ -20,12 +20,16 @@ import org.apache.jackrabbit.core.PropertyImpl; import org.apache.jackrabbit.core.NodeId; import org.apache.jackrabbit.core.ItemManager; +import org.apache.jackrabbit.core.HierarchyManager; import org.apache.jackrabbit.spi.commons.conversion.NameException; import org.apache.jackrabbit.spi.Name; +import org.apache.jackrabbit.spi.QValueFactory; +import org.apache.jackrabbit.spi.QValue; import org.apache.jackrabbit.spi.commons.name.NameConstants; import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl; import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver; -import org.apache.jackrabbit.value.ValueFactoryImpl; +import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl; +import org.apache.jackrabbit.spi.commons.value.ValueFactoryQImpl; import org.apache.jackrabbit.util.ISO9075; import org.slf4j.LoggerFactory; import org.slf4j.Logger; @@ -37,7 +41,6 @@ import javax.jcr.Value; import javax.jcr.PathNotFoundException; import javax.jcr.NamespaceException; -import javax.jcr.ValueFactory; import javax.jcr.Node; import javax.jcr.query.Row; import javax.jcr.query.RowIterator; @@ -61,9 +64,9 @@ private static final Logger log = LoggerFactory.getLogger(RowIteratorImpl.class); /** - * The value factory. + * The QValue factory. */ - private static final ValueFactory VALUE_FACTORY = ValueFactoryImpl.getInstance(); + private static final QValueFactory QVALUE_FACTORY = QValueFactoryImpl.getInstance(); /** * The name of the excerpt function without prefix but with left parenthesis. @@ -85,7 +88,7 @@ /** * Iterator over nodes, that constitute the result set. */ - private final ScoreNodeIterator nodes; + private final ScoreNodeIterator scoreNodes; /** * Array of select property names @@ -93,6 +96,11 @@ private final Name[] properties; /** + * Set of select property Names. + */ + private Set propertySet; + + /** * List of valid selector {@link Name}s. */ private final List selectorNames = new ArrayList(); @@ -103,6 +111,11 @@ private final ItemManager itemMgr; /** + * The hierarchy manager of the workspace. + */ + private final HierarchyManager hmgr; + + /** * The NamePathResolver of the user Session. */ private final NamePathResolver resolver; @@ -118,15 +131,21 @@ private final SpellSuggestion spellSuggestion; /** + * A value factory for the session that executes the query. + */ + private final ValueFactoryQImpl valueFactory; + + /** * Creates a new RowIteratorImpl that iterates over the result * nodes. * - * @param nodes a ScoreNodeIterator that contains the + * @param scoreNodes a ScoreNodeIterator that contains the * nodes of the query result. * @param properties Name of the select properties. * @param selectorNames the selector names. * @param itemMgr the item manager of the session that executes the * query. + * @param hmgr the hierarchy manager of the workspace. * @param resolver NamespaceResolver of the user * Session. * @param exProvider the excerpt provider associated with the query @@ -134,20 +153,23 @@ * @param spellSuggestion the spell suggestion associated with the query * result or null if none is available. */ - RowIteratorImpl(ScoreNodeIterator nodes, + RowIteratorImpl(ScoreNodeIterator scoreNodes, Name[] properties, Name[] selectorNames, ItemManager itemMgr, + HierarchyManager hmgr, NamePathResolver resolver, ExcerptProvider exProvider, SpellSuggestion spellSuggestion) { - this.nodes = nodes; + this.scoreNodes = scoreNodes; this.properties = properties; this.selectorNames.addAll(Arrays.asList(selectorNames)); this.itemMgr = itemMgr; + this.hmgr = hmgr; this.resolver = resolver; this.excerptProvider = exProvider; this.spellSuggestion = spellSuggestion; + this.valueFactory = new ValueFactoryQImpl(QVALUE_FACTORY, resolver); } /** @@ -158,8 +180,7 @@ * Rows. */ public Row nextRow() throws NoSuchElementException { - return new RowImpl(nodes.getScore(), - nodes.getScoreNodes(), nodes.nextNodeImpl()); + return new RowImpl(scoreNodes.nextScoreNodes()); } /** @@ -170,7 +191,7 @@ * Row in this iterator. */ public void skip(long skipNum) throws NoSuchElementException { - nodes.skip(skipNum); + scoreNodes.skip(skipNum); } /** @@ -179,7 +200,7 @@ * @return the number of Rows in this iterator. */ public long getSize() { - return nodes.getSize(); + return scoreNodes.getSize(); } /** @@ -193,7 +214,7 @@ * @return the current position withing this iterator. */ public long getPosition() { - return nodes.getPosition(); + return scoreNodes.getPosition(); } /** @@ -211,7 +232,7 @@ * @return true if the iterator has more elements. */ public boolean hasNext() { - return nodes.hasNext(); + return scoreNodes.hasNext(); } /** @@ -240,7 +261,7 @@ /** * The underlying Node of this result row. */ - private final NodeImpl node; + private NodeImpl node; /** * The score nodes associated with this row. @@ -253,21 +274,13 @@ private Value[] values; /** - * Set of select property Names. - */ - private Set propertySet; - - /** * Creates a new RowImpl instance based on node. * - * @param score the score value for this result row * @param sn the score nodes associated with this row. - * @param node the underlying Node for this Row. */ - RowImpl(float score, ScoreNode[] sn, NodeImpl node) { - this.score = score; + RowImpl(ScoreNode[] sn) { this.sn = sn; - this.node = node; + this.score = sn[0].getScore(); } /** @@ -283,11 +296,11 @@ if (values == null) { Value[] tmp = new Value[properties.length]; for (int i = 0; i < properties.length; i++) { - if (node.hasProperty(properties[i])) { - PropertyImpl prop = node.getProperty(properties[i]); + if (getNodeImpl().hasProperty(properties[i])) { + PropertyImpl prop = getNodeImpl().getProperty(properties[i]); if (!prop.getDefinition().isMultiple()) { if (prop.getDefinition().getRequiredType() == PropertyType.UNDEFINED) { - tmp[i] = VALUE_FACTORY.createValue(prop.getString()); + tmp[i] = valueFactory.createValue(prop.getString()); } else { tmp[i] = prop.getValue(); } @@ -299,9 +312,9 @@ // property not set or one of the following: // jcr:path / jcr:score / rep:excerpt / rep:spellcheck if (NameConstants.JCR_PATH.equals(properties[i])) { - tmp[i] = VALUE_FACTORY.createValue(node.getPath(), PropertyType.PATH); + tmp[i] = valueFactory.createValue(getNodeImpl().getPath(), PropertyType.PATH); } else if (NameConstants.JCR_SCORE.equals(properties[i])) { - tmp[i] = VALUE_FACTORY.createValue(Math.round(score * 1000f)); + tmp[i] = valueFactory.createValue(Math.round(score * 1000f)); } else if (isExcerptFunction(properties[i])) { tmp[i] = getExcerpt(); } else if (isSpellCheckFunction(properties[i])) { @@ -348,20 +361,21 @@ throw new ItemNotFoundException(propertyName); } } - if (node.hasProperty(prop)) { - Property p = node.getProperty(prop); + if (NameConstants.JCR_PATH.equals(prop)) { + QValue p = QVALUE_FACTORY.create(hmgr.getPath(sn[0].getNodeId())); + return valueFactory.createValue(p); + } else if (getNodeImpl().hasProperty(prop)) { + Property p = getNodeImpl().getProperty(prop); if (p.getDefinition().getRequiredType() == PropertyType.UNDEFINED) { - return VALUE_FACTORY.createValue(p.getString()); + return valueFactory.createValue(p.getString()); } else { return p.getValue(); } } else { - // either jcr:score, jcr:path, rep:excerpt, + // either jcr:score, rep:excerpt, // rep:spellcheck or not set - if (NameConstants.JCR_PATH.equals(prop)) { - return VALUE_FACTORY.createValue(node.getPath(), PropertyType.PATH); - } else if (NameConstants.JCR_SCORE.equals(prop)) { - return VALUE_FACTORY.createValue(Math.round(score * 1000f)); + if (NameConstants.JCR_SCORE.equals(prop)) { + return valueFactory.createValue(Math.round(score * 1000f)); } else if (isExcerptFunction(prop)) { return getExcerpt(); } else if (isSpellCheckFunction(prop)) { @@ -395,7 +409,7 @@ */ public Node getNode() throws RepositoryException { checkSingleSelector("Use getNode(String) instead."); - return node; + return getNodeImpl(); } /** @@ -430,7 +444,7 @@ */ public String getPath() throws RepositoryException { checkSingleSelector("Use getPath(String) instead."); - return node.getPath(); + return resolver.getJCRPath(hmgr.getPath(sn[0].getNodeId())); } /** @@ -510,6 +524,20 @@ //-----------------------------< internal >----------------------------- /** + * Returns the node corresponding to this row. + * + * @return the node. + * @throws RepositoryException if an error occurs while retrieving the + * node. e.g. node does not exist anymore. + */ + private NodeImpl getNodeImpl() throws RepositoryException { + if (node == null) { + node = (NodeImpl) itemMgr.getItem(sn[0].getNodeId()); + } + return node; + } + + /** * Checks if there is a single selector and otherwise throws a * RepositoryException. * @@ -573,7 +601,7 @@ * created or an error occurs. */ private Value getExcerpt() { - return createExcerpt(node.getNodeId()); + return createExcerpt(sn[0].getNodeId()); } /** @@ -597,12 +625,12 @@ idx + EXCERPT_FUNC_LPAR.length(), end).trim(); String decodedPath = ISO9075.decode(pathStr); try { - NodeImpl n = (NodeImpl) node.getNode(decodedPath); + NodeImpl n = (NodeImpl) getNodeImpl().getNode(decodedPath); return createExcerpt(n.getNodeId()); } catch (PathNotFoundException e) { // does not exist or references a property try { - Property p = node.getProperty(decodedPath); + Property p = getNode().getProperty(decodedPath); return highlight(p.getValue().getString()); } catch (PathNotFoundException e1) { // does not exist @@ -627,7 +655,7 @@ time = System.currentTimeMillis() - time; log.debug("Created excerpt in {} ms.", new Long(time)); if (excerpt != null) { - return VALUE_FACTORY.createValue(excerpt); + return valueFactory.createValue(excerpt); } else { return null; } @@ -652,7 +680,7 @@ text = hep.highlight(text); time = System.currentTimeMillis() - time; log.debug("Highlighted text in {} ms.", new Long(time)); - return VALUE_FACTORY.createValue(text); + return valueFactory.createValue(text); } catch (IOException e) { return null; } @@ -686,7 +714,7 @@ } } if (v != null) { - return VALUE_FACTORY.createValue(v); + return valueFactory.createValue(v); } else { return null; } Index: src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNodeIterator.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNodeIterator.java (revision 755749) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNodeIterator.java (working copy) @@ -16,45 +16,19 @@ */ package org.apache.jackrabbit.core.query.lucene; -import org.apache.jackrabbit.core.NodeImpl; +import javax.jcr.RangeIterator; -import javax.jcr.NodeIterator; - /** - * Extends the {@link javax.jcr.NodeIterator} interface by adding a {@link - * #getScore()} method that returns the score for the node that is returned by - * {@link javax.jcr.NodeIterator#nextNode()}. + * A range iterator over {@link ScoreNode}[]. */ -public interface ScoreNodeIterator extends NodeIterator { +public interface ScoreNodeIterator extends RangeIterator { /** - * Returns the score of the node returned by {@link #nextNode()}. In other - * words, this method returns the score value of the next - * Node. + * Returns the next score nodes. * - * @return the score of the node returned by {@link #nextNode()}. + * @return the next score nodes. * @throws java.util.NoSuchElementException - * if there is no next node. + * if there are no next score nodes. */ - float getScore(); - - /** - * Returns the score nodes related to the node returned by - * {@link #nextNodeImpl()} but does not move the iterator forward. - * - * @return the score nodes related to the {@link #nextNodeImpl()}. - * @throws java.util.NoSuchElementException - * if there is no next node. - */ - ScoreNode[] getScoreNodes(); - - /** - * Returns the next Node in the result set. - * - * @return the next Node in the result set. - * @throws java.util.NoSuchElementException - * if iteration has no more Nodes. - */ - NodeImpl nextNodeImpl(); - + ScoreNode[] nextScoreNodes(); } Index: src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNodeIteratorImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNodeIteratorImpl.java (revision 0) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/ScoreNodeIteratorImpl.java (revision 0) @@ -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.util.Collection; +import java.util.Arrays; + +import org.apache.jackrabbit.commons.iterator.RangeIteratorAdapter; + +/** + * ScoreNodeIteratorImpl implements a {@link ScoreNodeIterator} + * over an array of {@link ScoreNode ScoreNode[]}. + */ +public class ScoreNodeIteratorImpl + extends RangeIteratorAdapter + implements ScoreNodeIterator { + + public ScoreNodeIteratorImpl(ScoreNode[][] scoreNodes) { + super(Arrays.asList(scoreNodes)); + } + + /** + * {@inheritDoc} + */ + public ScoreNode[] nextScoreNodes() { + return (ScoreNode[]) next(); + } +} Property changes on: src\main\java\org\apache\jackrabbit\core\query\lucene\ScoreNodeIteratorImpl.java ___________________________________________________________________ Added: svn:eol-style + native Index: src/main/java/org/apache/jackrabbit/core/query/QueryHandlerContext.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/QueryHandlerContext.java (revision 755749) +++ src/main/java/org/apache/jackrabbit/core/query/QueryHandlerContext.java (working copy) @@ -19,10 +19,11 @@ import org.apache.jackrabbit.core.fs.FileSystem; import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry; import org.apache.jackrabbit.core.state.ItemStateManager; +import org.apache.jackrabbit.core.state.SharedItemStateManager; import org.apache.jackrabbit.core.NodeId; import org.apache.jackrabbit.core.NamespaceRegistryImpl; import org.apache.jackrabbit.core.HierarchyManager; -import org.apache.jackrabbit.core.HierarchyManagerImpl; +import org.apache.jackrabbit.core.CachingHierarchyManager; import org.apache.jackrabbit.core.persistence.PersistenceManager; /** @@ -40,12 +41,12 @@ /** * The persistent ItemStateManager */ - private final ItemStateManager stateMgr; + private final SharedItemStateManager stateMgr; /** * The hierarchy manager on top of {@link #stateMgr}. */ - private final HierarchyManager hmgr; + private final CachingHierarchyManager hmgr; /** * The underlying persistence manager. @@ -101,7 +102,7 @@ * excluded from indexing. */ public QueryHandlerContext(FileSystem fs, - ItemStateManager stateMgr, + SharedItemStateManager stateMgr, PersistenceManager pm, NodeId rootId, NodeTypeRegistry ntRegistry, @@ -110,7 +111,8 @@ NodeId excludedNodeId) { this.fs = fs; this.stateMgr = stateMgr; - this.hmgr = new HierarchyManagerImpl(rootId, stateMgr); + this.hmgr = new CachingHierarchyManager(rootId, stateMgr); + this.stateMgr.addListener(hmgr); this.pm = pm; this.rootId = rootId; this.ntRegistry = ntRegistry; Index: src/main/java/org/apache/jackrabbit/core/SearchManager.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/SearchManager.java (revision 755749) +++ src/main/java/org/apache/jackrabbit/core/SearchManager.java (working copy) @@ -27,9 +27,9 @@ import org.apache.jackrabbit.core.query.QueryHandlerContext; import org.apache.jackrabbit.core.query.QueryObjectModelImpl; import org.apache.jackrabbit.core.state.ItemStateException; -import org.apache.jackrabbit.core.state.ItemStateManager; import org.apache.jackrabbit.core.state.NodeState; import org.apache.jackrabbit.core.state.NodeStateIterator; +import org.apache.jackrabbit.core.state.SharedItemStateManager; import org.apache.jackrabbit.core.persistence.PersistenceManager; import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException; import org.apache.jackrabbit.spi.commons.query.jsr283.qom.QueryObjectModel; @@ -101,7 +101,7 @@ /** * The shared item state manager instance for the workspace. */ - private final ItemStateManager itemMgr; + private final SharedItemStateManager itemMgr; /** * The underlying persistence manager. @@ -164,7 +164,7 @@ public SearchManager(SearchConfig config, final NamespaceRegistryImpl nsReg, NodeTypeRegistry ntReg, - ItemStateManager itemMgr, + SharedItemStateManager itemMgr, PersistenceManager pm, NodeId rootNodeId, SearchManager parentMgr, Index: src/test/java/org/apache/jackrabbit/core/query/QueryResultTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/query/QueryResultTest.java (revision 755749) +++ src/test/java/org/apache/jackrabbit/core/query/QueryResultTest.java (working copy) @@ -210,11 +210,11 @@ QueryManager qm = superuser.getWorkspace().getQueryManager(); String stmt = testPath + "/*[@" + propertyName1 + " > 1000]"; QueryResult result = qm.createQuery(stmt, Query.XPATH).execute(); - NodeIterator it = result.getNodes(); - assertEquals("Wrong position", 0, it.getPosition()); + assertEquals("Wrong position", 0, result.getNodes().getPosition()); + assertEquals("Wrong position", 0, result.getRows().getPosition()); stmt += " order by jcr:score()"; result = qm.createQuery(stmt, Query.XPATH).execute(); - it = result.getNodes(); - assertEquals("Wrong position", 0, it.getPosition()); + assertEquals("Wrong position", 0, result.getNodes().getPosition()); + assertEquals("Wrong position", 0, result.getRows().getPosition()); } }