lazyqueryresultimpl.java
来自「jsr170接口的java实现。是个apache的开源项目。」· Java 代码 · 共 457 行
JAVA
457 行
/* * 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.NodeId;import org.apache.jackrabbit.core.NodeImpl;import org.apache.jackrabbit.core.security.AccessManager;import org.apache.jackrabbit.name.NamespaceResolver;import org.apache.jackrabbit.name.NoPrefixDeclaredException;import org.apache.jackrabbit.name.QName;import org.apache.jackrabbit.name.NameFormat;import org.apache.lucene.search.Query;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.jcr.NodeIterator;import javax.jcr.RepositoryException;import javax.jcr.ItemNotFoundException;import javax.jcr.Node;import javax.jcr.query.QueryResult;import javax.jcr.query.RowIterator;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.NoSuchElementException;/** * Implements the <code>javax.jcr.query.QueryResult</code> interface. */public class LazyQueryResultImpl implements QueryResult { /** * The logger instance for this class */ private static final Logger log = LoggerFactory.getLogger(QueryResultImpl.class); /** * The search index to execute the query. */ private final SearchIndex index; /** * The item manager of the session executing the query */ private final ItemManager itemMgr; /** * The namespace resolver of the session executing the query */ protected final NamespaceResolver resolver; /** * The access manager of the session that executes the query. */ private final AccessManager accessMgr; /** * The query instance which created this query result. */ protected final QueryImpl queryImpl; /** * The lucene query to execute. */ protected final Query query; /** * The select properties */ protected final QName[] selectProps; /** * The names of properties to use for ordering the result set. */ protected final QName[] orderProps; /** * The order specifier for each of the order properties. */ protected final boolean[] orderSpecs; /** * The result nodes including their score. This list is populated on a lazy * basis while a client iterates through the results. */ private final List resultNodes = new ArrayList(); /** * This is the raw number of results that matched the query. This number * also includes matches which will not be returned due to access * restrictions. This value is set when the query is executed the first * time. */ private int numResults = -1; /** * 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. */ private int invalid = 0; /** * If <code>true</code> nodes are returned in document order. */ private final boolean docOrder; /** * The excerpt provider or <code>null</code> if none was created yet. */ private ExcerptProvider excerptProvider; /** * Creates a new query result. * * @param index the search index where the query is executed. * @param itemMgr the item manager of the session executing the * query. * @param resolver the namespace resolver of the session executing the * query. * @param accessMgr the access manager of the session executiong the * query. * @param queryImpl the query instance which created this query result. * @param query the lucene query to execute on the index. * @param selectProps the select properties of the query. * @param orderProps the names of the order properties. * @param orderSpecs the order specs, one for each order property name. * @param documentOrder if <code>true</code> the result is returned in * document order. */ public LazyQueryResultImpl(SearchIndex index, ItemManager itemMgr, NamespaceResolver resolver, AccessManager accessMgr, QueryImpl queryImpl, Query query, QName[] selectProps, QName[] orderProps, boolean[] orderSpecs, boolean documentOrder) throws RepositoryException { this.index = index; this.itemMgr = itemMgr; this.resolver = resolver; this.accessMgr = accessMgr; this.queryImpl = queryImpl; this.query = query; this.selectProps = selectProps; this.orderProps = orderProps; this.orderSpecs = orderSpecs; this.docOrder = orderProps.length == 0 && documentOrder; // if document order is requested get all results right away getResults(docOrder ? Integer.MAX_VALUE : index.getResultFetchSize()); } /** * {@inheritDoc} */ public String[] getColumnNames() throws RepositoryException { try { String[] propNames = new String[selectProps.length]; for (int i = 0; i < selectProps.length; i++) { propNames[i] = NameFormat.format(selectProps[i], resolver); } return propNames; } catch (NoPrefixDeclaredException npde) { String msg = "encountered invalid property name"; log.debug(msg); throw new RepositoryException(msg, npde); } } /** * {@inheritDoc} */ public NodeIterator getNodes() throws RepositoryException { return getNodeIterator(); } /** * {@inheritDoc} */ public RowIterator getRows() throws RepositoryException { if (excerptProvider == null) { try { excerptProvider = index.createExcerptProvider(query); } catch (IOException e) { throw new RepositoryException(e); } } return new RowIteratorImpl(getNodeIterator(), selectProps, resolver, excerptProvider); } /** * Executes the query for this result and returns hits. The caller must * close the query hits when he is done using it. * * @return hits for this query result. * @throws IOException if an error occurs while executing the query. */ protected QueryHits executeQuery() throws IOException { return index.executeQuery(queryImpl, query, orderProps, orderSpecs); } //--------------------------------< internal >------------------------------ /** * Creates a node iterator over the result nodes. * * @return a node iterator over the result nodes. */ private ScoreNodeIterator getNodeIterator() { if (docOrder) { return new DocOrderNodeIteratorImpl(itemMgr, resultNodes); } else { return new LazyScoreNodeIterator(); } } /** * Attempts to get <code>size</code> results and puts them into {@link * #resultNodes}. If the size of {@link #resultNodes} is less than * <code>size</code> then there are no more than <code>resultNodes.size()</code> * results for this query. * * @param size the number of results to fetch for the query. * @throws RepositoryException if an error occurs while executing the * query. */ private void getResults(int size) throws RepositoryException { if (log.isDebugEnabled()) { log.debug("getResults(" + size + ")"); } if (resultNodes.size() >= size) { // we already have them all return; } // execute it QueryHits result = null; try { result = executeQuery(); // set num results with the first query execution if (numResults == -1) { numResults = result.length(); } int start = resultNodes.size() + invalid; int max = Math.min(result.length(), numResults); for (int i = start; i < max && resultNodes.size() < size; i++) { NodeId id = NodeId.valueOf(result.doc(i).get(FieldNames.UUID)); // check access try { if (accessMgr.isGranted(id, AccessManager.READ)) { resultNodes.add(new ScoreNode(id, result.score(i))); } else { invalid++; } } catch (ItemNotFoundException e) { // has been deleted meanwhile invalid++; } } } catch (IOException e) { log.error("Exception while executing query: ", e); // todo throw? } finally { if (result != null) { try { result.close(); } catch (IOException e) { log.warn("Unable to close query result: " + e); } } } } private final class LazyScoreNodeIterator implements ScoreNodeIterator { private int position = -1; private boolean initialized = false; private NodeImpl next; /** * {@inheritDoc} */ public float getScore() { initialize(); if (!hasNext()) { throw new NoSuchElementException(); } return ((ScoreNode) resultNodes.get(position)).getScore(); } /** * {@inheritDoc} */ public NodeImpl nextNodeImpl() { initialize(); if (next == null) { throw new NoSuchElementException(); } NodeImpl n = next; fetchNext(); return n; } /** * {@inheritDoc} */ public Node nextNode() { return nextNodeImpl(); } /** * {@inheritDoc} */ public void skip(long skipNum) { initialize(); if (skipNum < 0) { throw new IllegalArgumentException("skipNum must not be negative"); } if ((position + invalid + skipNum) > numResults) { throw new NoSuchElementException(); } if (skipNum == 0) { // do nothing } else { // attempt to get enough results try { getResults(position + invalid + (int) skipNum); if (resultNodes.size() >= position + skipNum) { // skip within already fetched results position += skipNum - 1; fetchNext(); } else { // not enough results after getResults() throw new NoSuchElementException(); } } catch (RepositoryException e) { throw new NoSuchElementException(e.getMessage()); } } } /** * {@inheritDoc} * <p/> * This value may shrink when the query result encounters non-existing * nodes or the session does not have access to a node. */ public long getSize() { return numResults - invalid; } /** * {@inheritDoc} */ public long getPosition() { initialize(); return position; } /** * @throws UnsupportedOperationException always. */ public void remove() { throw new UnsupportedOperationException("remove"); } /** * {@inheritDoc} */ public boolean hasNext() { initialize(); return next != null; } /** * {@inheritDoc} */ public Object next() { return nextNodeImpl(); } /** * Initializes this iterator but only if it is not yet initialized. */ private void initialize() { if (!initialized) { fetchNext(); initialized = true; } } /** * Fetches the next node to return by this iterator. If this method * returns and {@link #next} is <code>null</code> then there is no next * node. */ private void fetchNext() { next = null; int nextPos = position + 1; while (next == null && (nextPos + invalid) < numResults) { if (nextPos >= resultNodes.size()) { // fetch more results try { int num; if (resultNodes.size() == 0) { num = index.getResultFetchSize(); } else { num = resultNodes.size() * 2; } getResults(num); } catch (RepositoryException e) { log.warn("Exception getting more results: " + e); } // check again if (nextPos >= resultNodes.size()) { // no more valid results return; } } ScoreNode sn = (ScoreNode) resultNodes.get(nextPos); try { next = (NodeImpl) itemMgr.getItem(sn.getNodeId()); } catch (RepositoryException e) { log.warn("Exception retrieving Node with UUID: " + sn.getNodeId() + ": " + e.toString()); // remove score node and try next resultNodes.remove(nextPos); invalid++; } } position++; } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?