/**
* Copyright (C) 2001-2004 France Telecom R&D
*
* This library 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 2 of the License, or (at your option) any later version.
*
* This library 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 this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.objectweb.speedo.query.jdo;
import org.objectweb.jorm.api.PClassMapping;
import org.objectweb.jorm.mapper.rdb.lib.RdbPPolymorphicClass;
import org.objectweb.medor.api.EvaluationException;
import org.objectweb.medor.api.MedorException;
import org.objectweb.medor.eval.api.ConnectionResources;
import org.objectweb.medor.eval.api.QueryEvaluator;
import org.objectweb.medor.eval.lib.BasicEvaluationMetaData;
import org.objectweb.medor.eval.prefetch.api.IntermediaryPrefetchBuffer;
import org.objectweb.medor.eval.prefetch.api.PrefetchBuffer;
import org.objectweb.medor.eval.prefetch.lib.IntermediaryPrefetchBufferImpl;
import org.objectweb.medor.expression.api.ParameterOperand;
import org.objectweb.medor.query.api.QueryLeaf;
import org.objectweb.medor.query.api.QueryTree;
import org.objectweb.medor.tuple.api.TupleCollection;
import org.objectweb.speedo.api.ExceptionHelper;
import org.objectweb.speedo.pm.jdo.api.JDOPOManagerItf;
import org.objectweb.speedo.query.api.QueryDefinition;
import org.objectweb.util.monolog.api.BasicLevel;
import java.util.HashMap;
import java.util.Map;
import javax.jdo.JDOFatalException;
/**
* Represent a Medor query executed for a JDO query. It contains the query, the
* evaluator, a link to the SpeedoCompiledQuery and some information about
* the data prefetching. A JDO can correspond to several Medor query in case of
* inheritance for example.
*
* @author S.Chassande-Barrioz
*/
public class JDOQueryEvalContext {
/**
* The medor querytree representing the query
*/
public QueryTree query;
/**
* the evaluator of the query
*/
public QueryEvaluator evaluator;
/**
* is the index of the identifier (prefetch index too)
*/
public int pnIndex;
/**
* the PClassMapping of the prefetched class
*/
public PClassMapping pcm;
/**
* The original speedo compiled query
*/
public JDOCompiledSelectQuery sqc;
/**
* @param qt is the medor querytree representing the query
* @param sqc is the original speedo compiled query
*/
public JDOQueryEvalContext(QueryTree qt,
JDOCompiledSelectQuery sqc) {
query = qt;
this.sqc = sqc;
}
/**
* Executes the sub query
* @param pm is the current persistence manager
* @param pos is the parameter of the query
* @param connection is the way to reach the persistence support
* @return a TupleCollection containing the result
* @throws MedorException
*
*/
public TupleCollection eval(JDOPOManagerItf pm,
ParameterOperand[] pos,
Object connection,
QueryDefinition userqd) throws MedorException {
// Calculates and gets the required connection ressources for this query
ConnectionResources connRess =
evaluator.getRequiredConnectionResources();
Map evalMDMap = null;
if (userqd != null && (userqd.getIndexFirst() > 0
|| userqd.getIndexLast() < Integer.MAX_VALUE)) {
//range values specified
evalMDMap = new HashMap();
}
// Gets the QueryLeafs that require connections
QueryLeaf[] leafs = connRess.getRequiredQueryLeafConnection();
// Setting QueryLeaf's appropriated connection Object
for (int cpt = 0; (cpt < leafs.length); cpt++) {
connRess.setConnection(leafs[cpt], connection);
if (evalMDMap != null) {
//range values specified
BasicEvaluationMetaData evalMD = new BasicEvaluationMetaData();
evalMD.setLimitedRangeStartAt((int) userqd.getIndexFirst());
evalMD.setLimitedRangeSize((int) (userqd.getIndexLast() - userqd.getIndexFirst()));
evalMDMap.put(leafs[cpt], evalMD);
}
}
PrefetchBuffer prefetchBuffer = null;
if (pcm != null) {
boolean isPolymorphic = (pcm instanceof RdbPPolymorphicClass)
&& ((JDOQueryDefinitionImpl) sqc.getDefinition()).getIncludeSubClasses();
prefetchBuffer = sqc.getMapper().getPrefetchCache().createPrefetchBuffer(
sqc.getPrefetchBufferFactory(),
pcm, pm.currentTransaction(),
pnIndex,
pm.getMultithreaded(),
!isPolymorphic);
//if the class is polymorphic, register an intermediary prefetch buffer
if (isPolymorphic) {
IntermediaryPrefetchBuffer ipb = new IntermediaryPrefetchBufferImpl(
prefetchBuffer,
pcm.getIndexesTable(pcm));
if (!pcm.getPMapper().getPrefetchCache().registerPrefetchBuffer(
ipb, pcm, pm.currentTransaction())) {
throw new MedorException("No prefetch buffer registered for the pcm " + pcm.getClassName() + ".");
}
//register the prefetch buffer for all the subclasses
try{
//get the list of all the sub pclassmappings
PClassMapping[] subPCMs = pcm.getSubPCMs();
if (subPCMs != null) {
for (int i = 0; i < subPCMs.length; i++) {
//create an intermediary prefetchBuffer that has the prefetchBuffer
//of the superclass as delegate prefetch buffer
//and the association table for the pcm of the superclass
IntermediaryPrefetchBuffer intermediaryPb = new IntermediaryPrefetchBufferImpl(
prefetchBuffer,
subPCMs[i].getIndexesTable(pcm));
if (!subPCMs[i].getPMapper().getPrefetchCache().registerPrefetchBuffer(
intermediaryPb, subPCMs[i], pm.currentTransaction())) {
throw new MedorException("No prefetch buffer registered for the pcm " + subPCMs[i].getClassName() + ".");
}
}
}
}
catch(Exception e){
throw new MedorException("Error while trying to register the prefetchBuffer with the subclasses. ", e);
}
}
}
// Launching Medor Evaluator...
if (sqc.getLogger().isLoggable(BasicLevel.DEBUG)) {
sqc.getLogger().log(BasicLevel.DEBUG, "Parameters: " + posToString(pos));
}
TupleCollection queryResult = null;
try {
queryResult = evaluator.evaluate(pos, connRess, prefetchBuffer, evalMDMap);
} catch (EvaluationException e) {
throw new JDOFatalException(
"Impossible to evaluate the query: ",
ExceptionHelper.getNested(e)
);
}
return queryResult;
}
/**
* Produces a String representation of parameter for logging.
*/
protected String posToString(ParameterOperand[] pos) {
if (pos == null) {
return "null";
}
StringBuffer sb = new StringBuffer("[");
String sep = "";
for(int i=0; i<pos.length; i++) {
sb.append(sep);
sb.append("(name='");
sb.append("'");
sb.append(pos[i].getName());
sb.append("', value=");
sb.append(pos[i]);
sb.append(")");
}
sb.append("]");
return sb.toString();
}
}