/*
* Copyright (C) 2005-2012 BetaCONCEPT Limited
*
* This file is part of Astroboa.
*
* Astroboa is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Astroboa is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Astroboa. If not, see <http://www.gnu.org/licenses/>.
*/
package org.betaconceptframework.astroboa.engine.jcr.query;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DurationFormatUtils;
import org.betaconceptframework.astroboa.api.model.query.criteria.CmsCriteria;
import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder;
import org.betaconceptframework.astroboa.engine.jcr.util.JackrabbitDependentUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Gregory Chomatas (gchomatas@betaconcept.com)
* @author Savvas Triantafyllou (striantafyllou@betaconcept.com)
*
*/
public class CmsQueryHandler {
private final Logger logger = LoggerFactory.getLogger(CmsQueryHandler.class);
public CmsQueryResult getNodesFromXPathQuery(Session session, String xpathQuery,int offset, int limit) throws RepositoryException{
return getNodesFromXPathQuery(session, xpathQuery, offset, limit, true);
}
public CmsQueryResult getNodesFromXPathQuery(Session session, String xpathQuery,int offset, int limit, boolean retrieveNodeIterator) throws RepositoryException{
return getNodesFromQuery(session, xpathQuery, offset, limit, Query.XPATH, retrieveNodeIterator);
}
private CmsQueryResult getNodesFromQuery(Session session, String xpathQuery, int offset, int limit, String queryFormat, boolean retrieveNodeIterator) throws RepositoryException{
try{
QueryManager queryManager = session.getWorkspace().getQueryManager();
//Create Query object
if (StringUtils.isBlank(queryFormat) || ( ! Query.XPATH.equals(queryFormat) && !Query.SQL.equals(queryFormat)))
queryFormat = Query.XPATH;
Query query = queryManager.createQuery(xpathQuery, queryFormat);
//Inform query about offset and limit
setOffsetAndLimitToQuery(query, offset, limit);
//Run query
QueryResult queryResultForAllNodes = executeQuery(query);
//Get total number of nodes.
//It does not matter if any offset or limit are set, Jackrabbit knows
//how many nodes match criteria
int totalNumberOfNodesMatchingQueryCriteria = JackrabbitDependentUtils.getTotalNumberOfRowsForQueryResult(queryResultForAllNodes);
if (logger.isDebugEnabled()){
logger.debug("Found {} nodes matching criteria. Offset :{}, Limit : {}",
new Object[]{totalNumberOfNodesMatchingQueryCriteria, offset,limit});
JackrabbitDependentUtils.logCacheManagerSettings(logger, session.getRepository());
}
//Wrap results
if (retrieveNodeIterator){
return new CmsQueryResult(totalNumberOfNodesMatchingQueryCriteria, queryResultForAllNodes.getNodes());
}
else{
return new CmsQueryResult(totalNumberOfNodesMatchingQueryCriteria, queryResultForAllNodes.getRows());
}
}
catch(RepositoryException e){
logger.error("Exception thrown by executing the following query {}",xpathQuery);
throw e;
}
}
private QueryResult executeQuery(Query query) throws RepositoryException {
long start = System.currentTimeMillis();
QueryResult allNodes = query.execute();
if (logger.isDebugEnabled()){
long queryExecutionTime = System.currentTimeMillis() - start;
logger.debug("Repository {} : Executed in {} secs, query : {}",
new Object[]{AstroboaClientContextHolder.getActiveRepositoryId(),
DurationFormatUtils.formatDuration(queryExecutionTime, "ss.SSSS"),
query.getStatement()});
}
return allNodes;
}
public CmsQueryResult getNodesFromXPathQuery(Session session, CmsCriteria cmsCriteria, int offset, int limit) throws RepositoryException{
return getNodesFromXPathQuery(session, cmsCriteria, offset, limit, true);
}
public CmsQueryResult getNodesFromXPathQuery(Session session, CmsCriteria cmsCriteria, int offset, int limit, boolean retrieveNodeIterator) throws RepositoryException{
String pathQuery = cmsCriteria.getXPathQuery();
return getNodesFromXPathQuery(session, pathQuery, offset, limit, retrieveNodeIterator);
}
public CmsQueryResult getNodesFromXPathQuery(Session session,
CmsCriteria cmsCriteria) throws RepositoryException {
return getNodesFromXPathQuery(session, cmsCriteria, true);
}
public CmsQueryResult getNodesFromXPathQuery(Session session,
CmsCriteria cmsCriteria, boolean retrieveNodeIterator) throws RepositoryException {
return getNodesFromXPathQuery(session, cmsCriteria, cmsCriteria.getOffset(), cmsCriteria.getLimit(), retrieveNodeIterator);
}
public void setOffsetAndLimitToQuery(Query query, int offset, int limit) {
query.setOffset(offset);
if (limit > 0){
query.setLimit(limit);
}
else if (limit == 0){
//Jackrabbit uses limit only if this is greater than 0
//In all other cases it fetches all results.
//In Astroboa, however, limit 0 denotes that no result should be rendered,
//that is only result count is needed.
//So in order to 'limit' Jackrabbit to bring the minimum results possible
//we set the limit to 1. This way Jackrabbit will only bring one result
//which is acceptable since Astroboa requires no result to be fetched.
//Total result count is not affected at all by limit
query.setLimit(1);
}
}
}