/* * 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; import java.util.HashMap; import java.util.Map; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.query.InvalidQueryException; import javax.jcr.query.QueryResult; import javax.jcr.query.qom.Column; import javax.jcr.query.qom.Constraint; import javax.jcr.query.qom.Ordering; import javax.jcr.query.qom.QueryObjectModel; import javax.jcr.query.qom.Source; import org.apache.jackrabbit.api.stats.RepositoryStatistics.Type; import org.apache.jackrabbit.commons.query.QueryObjectModelBuilderRegistry; import org.apache.jackrabbit.core.query.lucene.LuceneQueryFactory; import org.apache.jackrabbit.core.query.lucene.SearchIndex; import org.apache.jackrabbit.core.query.lucene.join.QueryEngine; import org.apache.jackrabbit.core.session.SessionContext; import org.apache.jackrabbit.core.session.SessionOperation; import org.apache.jackrabbit.stats.RepositoryStatisticsImpl; import org.apache.jackrabbit.spi.commons.query.qom.BindVariableValueImpl; import org.apache.jackrabbit.spi.commons.query.qom.DefaultTraversingQOMTreeVisitor; import org.apache.jackrabbit.spi.commons.query.qom.QueryObjectModelTree; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * <code>QueryObjectModelImpl</code> implements the query object model. */ public class QueryObjectModelImpl extends QueryImpl implements QueryObjectModel { /** * The logger instance for this class */ private static final Logger log = LoggerFactory.getLogger(QueryObjectModelImpl.class); /** * The query object model tree. */ protected QueryObjectModelTree qomTree; /** Bind variables */ private final Map<String, Value> variables = new HashMap<String, Value>(); private LuceneQueryFactory lqf; /** * {@inheritDoc} * @throws UnsupportedOperationException always. */ @Override public void init( SessionContext sessionContext, QueryHandler handler, String statement, String language, Node node) throws InvalidQueryException { throw new UnsupportedOperationException(); } /** * Initializes a query instance from a query object model. * * @param sessionContext component context of the current session * @param handler the query handler of the search index. * @param qomTree the query object model tree. * @param language the original query syntax from where the JQOM was * created. * @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 qom tree cannot be serialized * according to the given language. * @throws RepositoryException if another error occurs */ public void init( SessionContext sessionContext, QueryHandler handler, QueryObjectModelTree qomTree, String language, Node node) throws InvalidQueryException, RepositoryException { checkNotInitialized(); this.sessionContext = sessionContext; this.language = language; this.handler = handler; this.qomTree = qomTree; this.node = node; this.statement = QueryObjectModelBuilderRegistry.getQueryObjectModelBuilder(language).toString(this); try { qomTree.accept(new DefaultTraversingQOMTreeVisitor() { @Override public Object visit(BindVariableValueImpl node, Object data) { variables.put(node.getBindVariableName(), null); return data; } }, null); } catch (Exception ignore) { } this.lqf = new LuceneQueryFactory( sessionContext.getSessionImpl(), (SearchIndex) handler, variables); setInitialized(); } public QueryResult execute() throws RepositoryException { long time = System.nanoTime(); final QueryResult result = sessionContext.getSessionState().perform( new SessionOperation<QueryResult>() { public QueryResult perform(SessionContext context) throws RepositoryException { final QueryEngine engine = new QueryEngine( sessionContext.getSessionImpl(), lqf, variables); return engine.execute(getColumns(), getSource(), getConstraint(), getOrderings(), offset, limit); } public String toString() { return "query.execute(" + statement + ")"; } }); time = System.nanoTime() - time; final long timeMs = time / 1000000; log.debug("executed in {} ms. ({})", timeMs, statement); RepositoryStatisticsImpl statistics = sessionContext .getRepositoryContext().getRepositoryStatistics(); statistics.getCounter(Type.QUERY_COUNT).incrementAndGet(); statistics.getCounter(Type.QUERY_DURATION).addAndGet(timeMs); sessionContext.getRepositoryContext().getStatManager().getQueryStat() .logQuery(language, statement, timeMs); return result; } @Override public String[] getBindVariableNames() { return variables.keySet().toArray(new String[variables.size()]); } @Override public void bindValue(String varName, Value value) throws IllegalArgumentException { if (variables.containsKey(varName)) { variables.put(varName, value); } else { throw new IllegalArgumentException( "No such bind variable: " + varName); } } //-------------------------< QueryObjectModel >----------------------------- /** * Gets the node-tuple source for this query. * * @return the node-tuple source; non-null */ public Source getSource() { return qomTree.getSource(); } /** * Gets the constraint for this query. * * @return the constraint, or null if none */ public Constraint getConstraint() { return qomTree.getConstraint(); } /** * Gets the orderings for this query. * * @return an array of zero or more orderings; non-null */ public Ordering[] getOrderings() { return qomTree.getOrderings(); } /** * Gets the columns for this query. * * @return an array of zero or more columns; non-null */ public Column[] getColumns() { return qomTree.getColumns(); } }