君子博学而日参省乎己 则知明而行无过矣

博客园 首页 新随笔 联系 订阅 管理

上文最后提到jackrabbit的检索默认实现类QueryImpl,先熟悉一下该类的继承层次

QueryImpl继承自抽象类AbstractQueryImpl,而抽象类实现了Query接口(JCR的接口)

Query接口源码如下: 

/**
 * A <code>Query</code> object.
 */
public interface Query {

    /**
     * A string constant representing the XPath query language as defined in JCR
     * 1.0.
     *
     * @deprecated As of JCR 2.0, this language is deprecated.
     */
    public static final String XPATH = "xpath";

    /**
     * A string constant representing the SQL query language as defined in JCR
     * 1.0.
     *
     * @deprecated As of JCR 2.0, this language is deprecated.
     */
    public static final String SQL = "sql";

    /**
     * A string constant representing the JCR-SQL2 query language.
     *
     * @since JCR 2.0
     */
    public static final String JCR_SQL2 = "JCR-SQL2";

    /**
     * A string constant representing the JCR-JQOM query language.
     *
     * @since JCR 2.0
     */
    public static final String JCR_JQOM = "JCR-JQOM";

    /**
     * Executes this query and returns a <code>{@link QueryResult}</code>
     * object.
     * <p>
     * If this <code>Query</code> contains a variable (see {@link
     * javax.jcr.query.qom.BindVariableValue BindVariableValue}) which has not
     * been bound to a value (see {@link Query#bindValue}) then this method
     * throws an <code>InvalidQueryException</code>.
     *
     * @return a <code>QueryResult</code> object
     * @throws InvalidQueryException if the query contains an unbound variable.
     * @throws RepositoryException   if another error occurs.
     */
    public QueryResult execute() throws InvalidQueryException, RepositoryException;

    /**
     * Sets the maximum size of the result set to <code>limit</code>.
     *
     * @param limit a <code>long</code>
     * @since JCR 2.0
     */
    public void setLimit(long limit);

    /**
     * Sets the start offset of the result set to <code>offset</code>.
     *
     * @param offset a <code>long</code>
     * @since JCR 2.0
     */
    public void setOffset(long offset);

    /**
     * Returns the statement defined for this query.
     * <p>
     * If the language of this query is JCR-SQL2 or another string-based
     * language, this method will return the statement that was used to create
     * this query.
     * <p>
     * If the language of this query is JCR-JQOM, this method will return the
     * JCR-SQL2 equivalent of the JCR-JQOM object tree. This is the standard
     * serialization of JCR-JQOM and is also the string stored in the
     * <code>jcr:statement</code> property if the query is persisted. See {@link
     * #storeAsNode(String)}.
     *
     * @return the query statement.
     */
    public String getStatement();

    /**
     * Returns the language set for this query. This will be one of the query
     * language constants returned by {@link QueryManager#getSupportedQueryLanguages}.
     *
     * @return the query language.
     */
    public String getLanguage();

    /**
     * If this is a <code>Query</code> object that has been stored using {@link
     * Query#storeAsNode} (regardless of whether it has been <code>save</code>d
     * yet) or retrieved using {@link QueryManager#getQuery}), then this method
     * returns the path of the <code>nt:query</code> node that stores the
     * query.
     *
     * @return path of the node representing this query.
     * @throws ItemNotFoundException if this query is not a stored query.
     * @throws RepositoryException   if another error occurs.
     */
    public String getStoredQueryPath() throws ItemNotFoundException, RepositoryException;

    /**
     * Creates a node of type <code>nt:query</code> holding this query at
     * <code>absPath</code> and returns that node.
     * <p>
     * This is  a session-write method and therefore requires a
     * <code>Session.save()</code> to dispatch the change.
     * <p>
     * The <code>absPath</code> provided must not have an index on its final
     * element. If ordering is supported by the node type of the parent node
     * then the new node is appended to the end of the child node list.
     * <p>
     * An <code>ItemExistsException</code> will be thrown either immediately, on
     * dispatch or on persists, if an item at the specified path already exists
     * and same-name siblings are not allowed. Implementations may differ on
     * when this validation is performed.
     * <p>
     * A <code>PathNotFoundException</code> will be thrown either immediately,
     * on dispatch or on persists, if the specified path implies intermediary
     * nodes that do not exist. Implementations may differ on when this
     * validation is performed.
     * <p>
     * A <code>ConstraintViolationException</code>will be thrown either
     * immediately, on dispatch or on persists, if adding the node would violate
     * a node type or implementation-specific constraint or if an attempt is
     * made to add a node as the child of a property. Implementations may differ
     * on when this validation is performed.
     * <p>
     * A <code>VersionException</code> will be thrown either immediately, on
     * dispatch or on persists, if the node to which the new child is being
     * added is read-only due to a checked-in node. Implementations may differ
     * on when this validation is performed.
     * <p>
     * A <code>LockException</code> will be thrown either immediately, on
     * dispatch or on persists, if a lock prevents the addition of the node.
     * Implementations may differ on when this validation is performed.
     *
     * @param absPath absolute path the query should be stored at
     * @return the newly created node.
     * @throws ItemExistsException          if an item at the specified path already
     *                                      exists, same-name siblings are not allowed and this implementation
     *                                      performs this validation immediately.
     * @throws PathNotFoundException        if the specified path implies intermediary
     *                                      <code>Node</code>s that do not exist or the last element of
     *                                      <code>relPath</code> has an index, and this implementation performs this
     *                                      validation immediately.
     * @throws ConstraintViolationException if a node type or
     *                                      implementation-specific constraint is violated or if an attempt is made
     *                                      to add a node as the child of a property and this implementation performs
     *                                      this validation immediately.
     * @throws VersionException             if the node to which the new child is being
     *                                      added is read-only due to a checked-in node and this implementation
     *                                      performs this validation immediately.
     * @throws LockException                if a lock prevents the addition of the node and
     *                                      this implementation performs this validation immediately.
     * @throws UnsupportedRepositoryOperationException
     *                                      if persistent queries are
     *                                      not supported.
     * @throws RepositoryException          if another error occurs or if the
     *                                      <code>absPath</code> provided has an index on its final element.
     */
    public Node storeAsNode(String absPath) throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, UnsupportedRepositoryOperationException, RepositoryException;

    /**
     * Binds the given <code>value</code> to the variable named
     * <code>varName</code>.
     *
     * @param varName name of variable in query
     * @param value   value to bind
     * @throws IllegalArgumentException      if <code>varName</code> is not a valid
     *                                       variable in this query.
     * @throws javax.jcr.RepositoryException if an error occurs.
     * @since JCR 2.0
     */
    public void bindValue(String varName, Value value) throws IllegalArgumentException, RepositoryException;

    /**
     * Returns the names of the bind variables in this query. If this query does
     * not contains any bind variables then an empty array is returned.
     *
     * @return the names of the bind variables in this query.
     * @throws RepositoryException if an error occurs.
     * @since JCR 2.0
     */
    public String[] getBindVariableNames() throws RepositoryException;
}

抽象类AbstractQueryImpl只有一个init抽象方法,显然是要求子类实现

/**
 * Defines common initialisation methods for all query implementations.
 */
public abstract class AbstractQueryImpl implements Query {

    /**
     * Initialises a query instance from a query string.
     *
     * @param sessionContext component context of the current session
     * @param handler   the query handler of the search index.
     * @param statement the query statement.
     * @param language  the syntax of the query statement.
     * @param node      a nt:query node where the query was read from or
     *                  <code>null</code> if it is not a stored query.
     * @throws InvalidQueryException if the query statement is invalid according
     *                               to the specified <code>language</code>.
     */
    public abstract void init(
            SessionContext sessionContext, QueryHandler handler,
            String statement, String language, Node node)
            throws InvalidQueryException;
}

QueryImpl类的源码如下:

/**
 * Provides the default implementation for a JCR query.
 */
public class QueryImpl extends AbstractQueryImpl {

    /**
     * The logger instance for this class
     */
    private static final Logger log = LoggerFactory.getLogger(QueryImpl.class);

    /**
     * Component context of the current session
     */
    protected SessionContext sessionContext;

    /**
     * The query statement
     */
    protected String statement;

    /**
     * The syntax of the query statement
     */
    protected String language;

    /**
     * The actual query implementation that can be executed
     */
    protected ExecutableQuery query;

    /**
     * The node where this query is persisted. Only set when this is a persisted
     * query.
     */
    protected Node node;

    /**
     * The query handler for this query.
     */
    protected QueryHandler handler;

    /**
     * Flag indicating whether this query is initialized.
     */
    private boolean initialized = false;

    /**
     * The maximum result size
     */
    protected long limit = -1;

    /**
     * The offset in the total result set
     */
    protected long offset = 0;

    /**
     * @inheritDoc
     */
    public void init(
            SessionContext sessionContext, QueryHandler handler,
            String statement, String language, Node node)
            throws InvalidQueryException {
        checkNotInitialized();
        this.sessionContext = sessionContext;
        this.statement = statement;
        this.language = language;
        this.handler = handler;
        this.node = node;
        this.query = handler.createExecutableQuery(sessionContext, statement, language);
        setInitialized();
    }

    /**
     * This method simply forwards the <code>execute</code> call to the
     * {@link ExecutableQuery} object returned by
     * {@link QueryHandler#createExecutableQuery}.
     * {@inheritDoc}
     */
    public QueryResult execute() throws RepositoryException {
        checkInitialized();
        long time = System.currentTimeMillis();
        QueryResult result = sessionContext.getSessionState().perform(
                new SessionOperation<QueryResult>() {
                    public QueryResult perform(SessionContext context)
                            throws RepositoryException {
                        return query.execute(offset, limit);
                    }
                    public String toString() {
                        return "query.execute(" + statement + ")";
                    }
                });
        if (log.isDebugEnabled()) {
            time = System.currentTimeMillis() - time;
            NumberFormat format = NumberFormat.getNumberInstance();
            format.setMinimumFractionDigits(2);
            format.setMaximumFractionDigits(2);
            String seconds = format.format((double) time / 1000);
            log.debug("executed in " + seconds + " s. (" + statement + ")");
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    public String getStatement() {
        checkInitialized();
        return statement;
    }

    /**
     * {@inheritDoc}
     */
    public String getLanguage() {
        checkInitialized();
        return language;
    }

    /**
     * {@inheritDoc}
     */
    public String getStoredQueryPath()
            throws ItemNotFoundException, RepositoryException {
        checkInitialized();
        if (node == null) {
            throw new ItemNotFoundException("not a persistent query");
        }
        return node.getPath();
    }

    /**
     * {@inheritDoc}
     */
    public Node storeAsNode(String absPath)
            throws ItemExistsException,
            PathNotFoundException,
            VersionException,
            ConstraintViolationException,
            LockException,
            UnsupportedRepositoryOperationException,
            RepositoryException {

        checkInitialized();
        try {
            Path p = sessionContext.getQPath(absPath).getNormalizedPath();
            if (!p.isAbsolute()) {
                throw new RepositoryException(absPath + " is not an absolute path");
            }

            String relPath = sessionContext.getJCRPath(p).substring(1);
            Node queryNode =
                sessionContext.getSessionImpl().getRootNode().addNode(
                        relPath, sessionContext.getJCRName(NT_QUERY));
            // set properties
            queryNode.setProperty(sessionContext.getJCRName(JCR_LANGUAGE), language);
            queryNode.setProperty(sessionContext.getJCRName(JCR_STATEMENT), statement);
            node = queryNode;
            return node;
        } catch (NameException e) {
            throw new RepositoryException(e.getMessage(), e);
        }
    }

    /**
     * {@inheritDoc}
     */
    public String[] getBindVariableNames() {
        return new String[0];
    }

    /**
     * Throws an {@link IllegalArgumentException} as XPath and SQL1 queries
     * have no bind variables.
     *
     * @throws IllegalArgumentException always thrown
     */
    public void bindValue(String varName, Value value)
            throws IllegalArgumentException {
        throw new IllegalArgumentException("No such bind variable: " + varName);
    }

    /**
     * Sets the maximum size of the result set.
     *
     * @param limit new maximum size of the result set
     */
    public void setLimit(long limit) {
        if (limit < 0) {
            throw new IllegalArgumentException("limit must not be negativ");
        }
        this.limit = limit;
    }

    /**
     * Sets the start offset of the result set.
     *
     * @param offset new start offset of the result set
     */
    public void setOffset(long offset) {
        if (offset < 0) {
            throw new IllegalArgumentException("offset must not be negativ");
        }
        this.offset = offset;
    }

    //-----------------------------< internal >---------------------------------

    /**
     * Sets the initialized flag.
     */
    protected void setInitialized() {
        initialized = true;
    }

    /**
     * Checks if this query is not yet initialized and throws an
     * <code>IllegalStateException</code> if it is already initialized.
     */
    protected void checkNotInitialized() {
        if (initialized) {
            throw new IllegalStateException("already initialized");
        }
    }

    /**
     * Checks if this query is initialized and throws an
     * <code>IllegalStateException</code> if it is not yet initialized.
     */
    protected void checkInitialized() {
        if (!initialized) {
            throw new IllegalStateException("not initialized");
        }
    }

}

先看一下它的初始化方法

 /**
     * @inheritDoc
     */
    public void init(
            SessionContext sessionContext, QueryHandler handler,
            String statement, String language, Node node)
            throws InvalidQueryException {
        checkNotInitialized();
        this.sessionContext = sessionContext;
        this.statement = statement;
        this.language = language;
        this.handler = handler;
        this.node = node;
        this.query = handler.createExecutableQuery(sessionContext, statement, language);
        setInitialized();
    }

这里的handler还是SearchManager初始化该类时传过来的SearchIndex类型的对象,我们从这里可以看到,ExecutableQuery类型的query成员变量时通过handler(SearchIndex类型)创建的

/**
     * The actual query implementation that can be executed
     */
    protected ExecutableQuery query;

QueryImpl类的真正检索方法如下:

/**
     * This method simply forwards the <code>execute</code> call to the
     * {@link ExecutableQuery} object returned by
     * {@link QueryHandler#createExecutableQuery}.
     * {@inheritDoc}
     */
    public QueryResult execute() throws RepositoryException {
        checkInitialized();
        long time = System.currentTimeMillis();
        QueryResult result = sessionContext.getSessionState().perform(
                new SessionOperation<QueryResult>() {
                    public QueryResult perform(SessionContext context)
                            throws RepositoryException {
                        return query.execute(offset, limit);
                    }
                    public String toString() {
                        return "query.execute(" + statement + ")";
                    }
                });
        if (log.isDebugEnabled()) {
            time = System.currentTimeMillis() - time;
            NumberFormat format = NumberFormat.getNumberInstance();
            format.setMinimumFractionDigits(2);
            format.setMaximumFractionDigits(2);
            String seconds = format.format((double) time / 1000);
            log.debug("executed in " + seconds + " s. (" + statement + ")");
        }
        return result;
    }

我们可以看到是调用ExecutableQuery query成员变量的execute方法

现在回顾头来查看一下SearchIndex的createExecutableQuery方法

/**
     * Creates a new query by specifying the query statement itself and the
     * language in which the query is stated.  If the query statement is
     * syntactically invalid, given the language specified, an
     * InvalidQueryException is thrown. <code>language</code> must specify a query language
     * string from among those returned by QueryManager.getSupportedQueryLanguages(); if it is not
     * then an <code>InvalidQueryException</code> is thrown.
     *
     * @param sessionContext component context of the current session
     * @param statement the query statement.
     * @param language the syntax of the query statement.
     * @throws InvalidQueryException if statement is invalid or language is unsupported.
     * @return A <code>Query</code> object.
     */
    public ExecutableQuery createExecutableQuery(
            SessionContext sessionContext, String statement, String language)
            throws InvalidQueryException {
        QueryImpl query = new QueryImpl(
                sessionContext, this, getContext().getPropertyTypeRegistry(),
                statement, language, getQueryNodeFactory());
        query.setRespectDocumentOrder(documentOrder);
        return query;
    }

可以看到,该方法实际返回的是org.apache.jackrabbit.core.query.lucene.QueryImpl类型的对象

org.apache.jackrabbit.core.query.lucene.QueryImpl类继承自抽象类org.apache.jackrabbit.core.query.lucene.AbstractQueryImpl,而抽象类org.apache.jackrabbit.core.query.lucene.AbstractQueryImpl实现了org.apache.jackrabbit.core.query.ExecutableQuery接口

(这里面命名与org.apache.jackrabbit.core.query包命名相同,容易使人混淆)

ExecutableQuery接口的源码如下:

/**
 * Specifies an interface for a query object implementation that can just be
 * executed.
 * @see QueryImpl
 */
public interface ExecutableQuery {

    /**
     * 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
     *
     * @return a <code>QueryResult</code>
     * @throws RepositoryException if an error occurs
     */
    QueryResult execute(long offset, long limit) throws RepositoryException;

}

 

抽象类org.apache.jackrabbit.core.query.lucene.AbstractQueryImpl源码如下:

/**
 * <code>AbstractQueryImpl</code> provides a base class for executable queries
 * based on {@link SearchIndex}.
 */
public abstract class AbstractQueryImpl implements ExecutableQuery {

    /**
     * Component context of the current session
     */
    protected final SessionContext sessionContext;

    /**
     * The actual search index
     */
    protected final SearchIndex index;

    /**
     * The property type registry for type lookup.
     */
    protected final PropertyTypeRegistry propReg;

    /**
     * If <code>true</code> the default ordering of the result nodes is in
     * document order.
     */
    private boolean documentOrder = true;

    protected final PerQueryCache cache = new PerQueryCache();

    /**
     * Creates a new query instance from a query string.
     *
     * @param sessionContext component context of the current session
     * @param index   the search index.
     * @param propReg the property type registry.
     */
    public AbstractQueryImpl(
            SessionContext sessionContext, SearchIndex index,
            PropertyTypeRegistry propReg) {
        this.sessionContext = sessionContext;
        this.index = index;
        this.propReg = propReg;
    }

    /**
     * If set <code>true</code> the result nodes will be in document order
     * per default (if no order by clause is specified). If set to
     * <code>false</code> the result nodes are returned in whatever sequence
     * the index has stored the nodes. That sequence is stable over multiple
     * invocations of the same query, but will change when nodes get added or
     * removed from the index.
     * <p/>
     * The default value for this property is <code>true</code>.
     * @return the current value of this property.
     */
    public boolean getRespectDocumentOrder() {
        return documentOrder;
    }

    /**
     * Sets a new value for this property.
     *
     * @param documentOrder if <code>true</code> the result nodes are in
     * document order per default.
     *
     * @see #getRespectDocumentOrder()
     */
    public void setRespectDocumentOrder(boolean documentOrder) {
        this.documentOrder = documentOrder;
    }

    /**
     * @return the query object model factory.
     * @throws RepositoryException if an error occurs.
     */
    protected QueryObjectModelFactory getQOMFactory()
            throws RepositoryException {
        Workspace workspace = sessionContext.getSessionImpl().getWorkspace();
        return workspace.getQueryManager().getQOMFactory();
    }

    /**
     * Returns <code>true</code> if this query node needs items under
     * /jcr:system to be queried.
     *
     * @return <code>true</code> if this query node needs content under
     *         /jcr:system to be queried; <code>false</code> otherwise.
     */
    public abstract boolean needsSystemTree();
}

org.apache.jackrabbit.core.query.lucene.QueryImpl类的源码如下:

/**
 * Implements the {@link org.apache.jackrabbit.core.query.ExecutableQuery}
 * interface.
 */
public class QueryImpl extends AbstractQueryImpl {

    /**
     * The logger instance for this class
     */
    private static final Logger log = LoggerFactory.getLogger(QueryImpl.class);

    /**
     * The default selector name 's'.
     */
    public static final Name DEFAULT_SELECTOR_NAME = NameFactoryImpl.getInstance().create("", "s");

    /**
     * The root node of the query tree
     */
    protected final QueryRootNode root;

    /**
     * Creates a new query instance from a query string.
     *
     * @param sessionContext component context of the current session
     * @param index     the search index.
     * @param propReg   the property type registry.
     * @param statement the query statement.
     * @param language  the syntax of the query statement.
     * @param factory   the query node factory.
     * @throws InvalidQueryException if the query statement is invalid according
     *                               to the specified <code>language</code>.
     */
    public QueryImpl(
            SessionContext sessionContext, SearchIndex index,
            PropertyTypeRegistry propReg, String statement, String language,
            QueryNodeFactory factory) throws InvalidQueryException {
        super(sessionContext, index, propReg);
        // parse query according to language
        // build query tree using the passed factory
        this.root = QueryParser.parse(
                statement, language, sessionContext, factory);
    }

    /**
     * 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
     * @return a <code>QueryResult</code>
     * @throws RepositoryException if an error occurs
     */
    public QueryResult execute(long offset, long limit) throws RepositoryException {
        if (log.isDebugEnabled()) {
            log.debug("Executing query: \n" + root.dump());
        }

        // build lucene query
        Query query = LuceneQueryBuilder.createQuery(
                root, sessionContext.getSessionImpl(),
                index.getContext().getItemStateManager(),
                index.getNamespaceMappings(), index.getTextAnalyzer(),
                propReg, index.getSynonymProvider(),
                index.getIndexFormatVersion(),
                cache);

        OrderQueryNode orderNode = root.getOrderNode();

        OrderQueryNode.OrderSpec[] orderSpecs;
        if (orderNode != null) {
            orderSpecs = orderNode.getOrderSpecs();
        } else {
            orderSpecs = new OrderQueryNode.OrderSpec[0];
        }
        Path[] orderProperties = new Path[orderSpecs.length];
        boolean[] ascSpecs = new boolean[orderSpecs.length];
        for (int i = 0; i < orderSpecs.length; i++) {
            orderProperties[i] = orderSpecs[i].getPropertyPath();
            ascSpecs[i] = orderSpecs[i].isAscending();
        }

        return new SingleColumnQueryResult(
                index, sessionContext, this, query,
                new SpellSuggestion(index.getSpellChecker(), root),
                getColumns(), orderProperties, ascSpecs,
                orderProperties.length == 0 && getRespectDocumentOrder(),
                offset, limit);
    }

    /**
     * Returns the columns for this query.
     *
     * @return array of columns.
     * @throws RepositoryException if an error occurs.
     */
    protected ColumnImpl[] getColumns() throws RepositoryException {
        SessionImpl session = sessionContext.getSessionImpl();
        QueryObjectModelFactory qomFactory =
            session.getWorkspace().getQueryManager().getQOMFactory();
        // get columns
        Map<Name, ColumnImpl> columns = new LinkedHashMap<Name, ColumnImpl>();
        for (Name name : root.getSelectProperties()) {
            String pn = sessionContext.getJCRName(name);
            ColumnImpl col = (ColumnImpl) qomFactory.column(
                    sessionContext.getJCRName(DEFAULT_SELECTOR_NAME), pn, pn);
            columns.put(name, col);
        }
        if (columns.size() == 0) {
            // use node type constraint
            LocationStepQueryNode[] steps = root.getLocationNode().getPathSteps();
            final Name[] ntName = new Name[1];
            steps[steps.length - 1].acceptOperands(new DefaultQueryNodeVisitor() {

                public Object visit(AndQueryNode node, Object data) throws RepositoryException {
                    return node.acceptOperands(this, data);
                }

                public Object visit(NodeTypeQueryNode node, Object data) {
                    ntName[0] = node.getValue();
                    return data;
                }
            }, null);
            if (ntName[0] == null) {
                ntName[0] = NameConstants.NT_BASE;
            }
            NodeTypeImpl nt = session.getNodeTypeManager().getNodeType(ntName[0]);
            PropertyDefinition[] propDefs = nt.getPropertyDefinitions();
            for (PropertyDefinition pd : propDefs) {
                QPropertyDefinition propDef = ((PropertyDefinitionImpl) pd).unwrap();
                if (!propDef.definesResidual() && !propDef.isMultiple()) {
                    columns.put(propDef.getName(), columnForName(propDef.getName()));
                }
            }
        }

        // add jcr:path and jcr:score if not selected already
        if (!columns.containsKey(NameConstants.JCR_PATH)) {
            columns.put(NameConstants.JCR_PATH, columnForName(NameConstants.JCR_PATH));
        }
        if (!columns.containsKey(NameConstants.JCR_SCORE)) {
            columns.put(NameConstants.JCR_SCORE, columnForName(NameConstants.JCR_SCORE));
        }

        return columns.values().toArray(new ColumnImpl[columns.size()]);
    }

    /**
     * Returns <code>true</code> if this query node needs items under
     * /jcr:system to be queried.
     *
     * @return <code>true</code> if this query node needs content under
     *         /jcr:system to be queried; <code>false</code> otherwise.
     */
    public boolean needsSystemTree() {
        return this.root.needsSystemTree();
    }

    /**
     * Returns a column for the given property name and the default selector
     * name.
     *
     * @param propertyName the name of the property as well as the column.
     * @return a column.
     * @throws RepositoryException if an error occurs while creating the column.
     */
    protected ColumnImpl columnForName(Name propertyName) throws RepositoryException {
        Workspace workspace = sessionContext.getSessionImpl().getWorkspace();
        QueryObjectModelFactory qomFactory =
            workspace.getQueryManager().getQOMFactory();
        String name = sessionContext.getJCRName(propertyName);
        return (ColumnImpl) qomFactory.column(
                sessionContext.getJCRName(DEFAULT_SELECTOR_NAME), name, name);
    }
}

最重要的查询方法是

/**
     * 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
     * @return a <code>QueryResult</code>
     * @throws RepositoryException if an error occurs
     */
    public QueryResult execute(long offset, long limit) throws RepositoryException {
        if (log.isDebugEnabled()) {
            log.debug("Executing query: \n" + root.dump());
        }

        // build lucene query
        Query query = LuceneQueryBuilder.createQuery(
                root, sessionContext.getSessionImpl(),
                index.getContext().getItemStateManager(),
                index.getNamespaceMappings(), index.getTextAnalyzer(),
                propReg, index.getSynonymProvider(),
                index.getIndexFormatVersion(),
                cache);

        OrderQueryNode orderNode = root.getOrderNode();

        OrderQueryNode.OrderSpec[] orderSpecs;
        if (orderNode != null) {
            orderSpecs = orderNode.getOrderSpecs();
        } else {
            orderSpecs = new OrderQueryNode.OrderSpec[0];
        }
        Path[] orderProperties = new Path[orderSpecs.length];
        boolean[] ascSpecs = new boolean[orderSpecs.length];
        for (int i = 0; i < orderSpecs.length; i++) {
            orderProperties[i] = orderSpecs[i].getPropertyPath();
            ascSpecs[i] = orderSpecs[i].isAscending();
        }

        return new SingleColumnQueryResult(
                index, sessionContext, this, query,
                new SpellSuggestion(index.getSpellChecker(), root),
                getColumns(), orderProperties, ascSpecs,
                orderProperties.length == 0 && getRespectDocumentOrder(),
                offset, limit);
    }

---------------------------------------------------------------------------

本系列Apache Jackrabbit源码研究系本人原创

转载请注明出处 博客园 刺猬的温驯

本文链接 http://www.cnblogs.com/chenying99/archive/2013/04/07/3003304.html

posted on 2013-04-07 03:29  刺猬的温驯  阅读(813)  评论(0编辑  收藏  举报