001: /**
002: * Copyright (C) 2001-2006 France Telecom R&D
003: */package org.objectweb.speedo.query.jdo;
004:
005: import org.objectweb.jorm.api.PMapper;
006: import org.objectweb.jorm.lib.JormPathHelper;
007: import org.objectweb.jorm.type.api.PType;
008: import org.objectweb.medor.api.EvaluationException;
009: import org.objectweb.medor.api.MedorException;
010: import org.objectweb.medor.eval.prefetch.api.PrefetchBufferFactory;
011: import org.objectweb.medor.expression.api.ExpressionException;
012: import org.objectweb.medor.expression.api.ParameterOperand;
013: import org.objectweb.medor.expression.lib.BasicParameterOperand;
014: import org.objectweb.medor.optim.api.QueryTransformer;
015: import org.objectweb.medor.optim.jorm.Jorm2Rdb;
016: import org.objectweb.medor.optim.lib.BasicQueryRewriter;
017: import org.objectweb.medor.optim.lib.FlattenQueryTreeRule;
018: import org.objectweb.medor.optim.lib.IndexesGenerator;
019: import org.objectweb.medor.optim.lib.PushNotInExpressionRule;
020: import org.objectweb.medor.optim.rdb.Like2SQL;
021: import org.objectweb.medor.query.api.QueryTree;
022: import org.objectweb.medor.query.jorm.lib.JormQueryTreeHelper;
023: import org.objectweb.medor.query.lib.QueryTreePrinter;
024: import org.objectweb.medor.type.lib.PTypeSpaceMedor;
025: import org.objectweb.medor.type.lib.QType;
026: import org.objectweb.perseus.persistence.api.PersistenceException;
027: import org.objectweb.speedo.api.SpeedoException;
028: import org.objectweb.speedo.lib.Personality;
029: import org.objectweb.speedo.mapper.api.JormFactory;
030: import org.objectweb.speedo.mapper.lib.DelegatePMapper;
031: import org.objectweb.speedo.mim.api.PersistentObjectItf;
032: import org.objectweb.speedo.pm.api.POManagerItf;
033: import org.objectweb.speedo.pm.jdo.api.JDOPOManagerItf;
034: import org.objectweb.speedo.query.api.QueryDefinition;
035: import org.objectweb.speedo.query.lib.AbstractCompiledQuery;
036: import org.objectweb.speedo.workingset.jdo.api.JDOTransactionItf;
037: import org.objectweb.util.monolog.api.BasicLevel;
038: import org.objectweb.util.monolog.api.Logger;
039:
040: import java.util.ArrayList;
041: import java.util.HashMap;
042: import java.util.Iterator;
043: import java.util.Map;
044: import java.util.StringTokenizer;
045:
046: import javax.jdo.JDOException;
047: import javax.jdo.JDOUserException;
048:
049: public abstract class JDOAbstractCompiledQuery extends
050: AbstractCompiledQuery {
051:
052: /**
053: * Fields from javax.jdo.Query
054: */
055: protected JDOQueryDefinitionImpl qd = null;
056:
057: /**
058: * vparams, hparams and hvars are internal objects to manipulate the list of
059: * parameters, and the list of variables.
060: */
061: protected Map hparams = null;
062:
063: protected Map paramName2paramClass = null;
064:
065: protected Map hvars = null;
066:
067: protected Logger varParserlogger = null;
068:
069: protected Logger filterParserLogger = null;
070:
071: protected abstract Object executeQT(JDOPOManagerItf pm,
072: ParameterOperand[] pos, QueryDefinition userqd)
073: throws EvaluationException, MedorException, SpeedoException;
074:
075: public void init(Logger l, Logger logParserVar,
076: Logger logParserFil, PMapper m, PrefetchBufferFactory pbf,
077: JormFactory _jf) {
078: init(l, m, pbf, _jf);
079: varParserlogger = logParserVar;
080: filterParserLogger = logParserFil;
081: }
082:
083: public void setMapper(PMapper m) {
084: mapper = new DelegatePMapper(m, Personality.JDO);
085: if (jf != null) {
086: mapper.setJormFactory(jf);
087: }
088: }
089:
090: public boolean isPrefetchResult() {
091: return qd.withPrefetch;
092: }
093:
094: public void defineQuery(JDOQueryDefinitionImpl _qd) {
095: this .qd = new JDOQueryDefinitionImpl(_qd);
096: classLoader = _qd.getCandidateClass().getClassLoader();
097: if (classLoader == null) {
098: classLoader = getClass().getClassLoader();
099: if (classLoader == null) {
100: classLoader = ClassLoader.getSystemClassLoader();
101: logger.log(BasicLevel.DEBUG,
102: "The system classLoader of the "
103: + "class is assigned to the query: "
104: + classLoader);
105: } else {
106: logger
107: .log(BasicLevel.DEBUG,
108: "The classLoader of Speedo is"
109: + " assigned the query: "
110: + classLoader);
111: }
112: } else {
113: logger.log(BasicLevel.DEBUG,
114: "The classLoader of the class is "
115: + "assigned to the query: " + classLoader);
116: }
117: mapper.setClassLoader(classLoader);
118: status = DEFINED;
119: }
120:
121: // IMPLEMENTATION OF ReplaceableCacheEntry INTERFACE //
122: // ---------------------------------------------------//
123: public Object getCeIdentifier() {
124: return qd;
125: }
126:
127: // IMPLEMENTATION OF CompiledQuery INTERFACE //
128: // -------------------------------------------//
129: public synchronized QueryDefinition getDefinition() {
130: switch (status) {
131: case DEFINED:
132: case COMPILED:
133: return qd;
134: case UNDEFINED:
135: default:
136: return null;
137: }
138: }
139:
140: protected QueryTree optimize(QueryTree qt, boolean debug)
141: throws MedorException, ExpressionException {
142: ArrayList rules = new ArrayList();
143: rules.add(new PushNotInExpressionRule());
144: if (mapper.getMapperName().startsWith("rdb")) {
145: rules.add(new FlattenQueryTreeRule());
146: rules.add(new Jorm2Rdb());
147: rules.add(new Like2SQL());
148: } else {
149:
150: }
151: QueryTree optimizedQT = qt;
152: QueryTransformer queryTransformer = new BasicQueryRewriter(
153: rules);
154: IndexesGenerator indexesGenerator = new IndexesGenerator();
155: try {
156: optimizedQT = queryTransformer.transform(optimizedQT);
157: if (debug) {
158: logger.log(BasicLevel.DEBUG, "Query optimized");
159: QueryTreePrinter.printQueryTree(optimizedQT, logger);
160: }
161: optimizedQT = indexesGenerator.transform(optimizedQT);
162: } catch (Exception e) {
163: throw new MedorException(
164: "Impossible to optimize the query", e);
165: }
166:
167: pncParams = JormQueryTreeHelper
168: .getRequiredPNameManagers(optimizedQT);
169: for (Iterator it = pncParams.iterator(); it.hasNext();) {
170: ParameterOperand po = (ParameterOperand) it.next();
171: String name = po.getName();
172: if (debug) {
173: logger.log(BasicLevel.DEBUG, "ParameterOperand " + name
174: + " is expected.");
175: }
176: po.setValue(JormPathHelper.getPNameCoder(name, mapper));
177: }
178: return optimizedQT;
179: }
180:
181: /**
182: * evaluate the query with a single parameter which is a array of object
183: * parameters.
184: * @param pm the persistence manager object
185: * @param a the array parameter of the query
186: * @return a Collection of result objects
187: * @throws org.objectweb.medor.api.EvaluationException
188: * @throws org.objectweb.medor.api.MedorException
189: */
190: public Object execute(Object[] a, POManagerItf pm,
191: QueryDefinition userqd) throws SpeedoException,
192: MedorException, ExpressionException {
193: if (status != COMPILED)
194: throw new EvaluationException(
195: "Impossible to execute a query if it has not been defined and compiled before");
196: ParameterOperand[] pos = null;
197: if (a != null) {
198: pos = new ParameterOperand[a.length + pncParams.size()];
199: for (Iterator it = hparams.values().iterator(); it
200: .hasNext();) {
201: Object[] o = (Object[]) it.next();
202: int idx = ((Integer) o[0]).intValue();
203: pos[idx] = new BasicParameterOperand(
204: (BasicParameterOperand) o[1]);
205: treatParameter(pos[idx], a[idx]);
206: }
207: } else {
208: pos = new ParameterOperand[pncParams.size()];
209: }
210: if (pncParams.size() > 0) {
211: int i = (a == null ? 0 : a.length);
212: for (Iterator it = pncParams.iterator(); it.hasNext(); i++) {
213: pos[i++] = (ParameterOperand) it.next();
214: }
215: }
216: return executeQT((JDOPOManagerItf) pm, pos, userqd);
217: }
218:
219: /**
220: * evaluate the query with a single parameter which is a Map of object parameters.
221: * @param pm the persistence manager object
222: * @param m the map parameter of the query
223: * @return a Collection of result objects
224: * @throws org.objectweb.medor.api.EvaluationException
225: * @throws org.objectweb.medor.api.MedorException
226: */
227: public Object execute(Map m, POManagerItf pm, QueryDefinition userqd)
228: throws SpeedoException, MedorException, ExpressionException {
229: if (status != COMPILED)
230: throw new EvaluationException(
231: "Impossible to execute a query if it has not been defined and compiled before");
232: ParameterOperand[] pos = new BasicParameterOperand[m.size()
233: + pncParams.size()];
234: for (Iterator it = hparams.values().iterator(); it.hasNext();) {
235: Object[] o = (Object[]) it.next();
236: int idx = ((Integer) o[0]).intValue();
237: pos[idx] = new BasicParameterOperand(
238: (BasicParameterOperand) o[1]);
239: treatParameter(pos[idx], m.get(pos[idx].getName()));
240: }
241: if (pncParams.size() > 0) {
242: int i = (m == null ? 0 : m.size());
243: for (Iterator it = pncParams.iterator(); it.hasNext(); i++) {
244: pos[i++] = (ParameterOperand) it.next();
245: }
246: }
247: return executeQT((JDOPOManagerItf) pm, pos, userqd);
248: }
249:
250: protected void treatParameter(ParameterOperand po, Object value)
251: throws SpeedoException, ExpressionException {
252: Object val = value;
253: if (po.getType().getTypeCode() == QType.TYPECODE_PNAME) {
254: //Assign the pname of the parameter
255: if (val == null) {
256: try {
257: val = jf.getPClassMapping(
258: (Class) paramName2paramClass.get(po
259: .getName())).getPBinder().getNull();
260: } catch (Exception e) {
261: throw new SpeedoException(
262: "Impossible to find the null PName of the parameter (name= "
263: + po.getName() + " / type= "
264: + po.getType().getJormName(), e);
265: }
266: } else if (val instanceof PersistentObjectItf) {
267: val = ((PersistentObjectItf) value).getPName();
268: } else {
269: throw new JDOUserException("The parameter '"
270: + po.getName()
271: + "' must be a persistent object: " + val);
272: }
273: }
274: po.setValue(val);
275: }
276:
277: // Private Methods //
278: //-----------------//
279:
280: /**
281: * Hash a String, and compute a Hashtable
282: * example:
283: * ("String name, Float salary, Employee boss", ",")
284: * keys | values
285: * ---------------------
286: * "name" | "String"
287: * "salary" | "Float"
288: * "boss" | "Employee"
289: *
290: * @param stringToHash the String to hash
291: * @param separator the separator to tokenize
292: */
293: protected void toHashtableParams(String stringToHash,
294: String separator) {
295: hparams = new HashMap();
296: paramName2paramClass = new HashMap();
297: if (stringToHash != null) {
298: StringTokenizer tok = new StringTokenizer(stringToHash,
299: separator);
300: int idx = 0;
301: while (tok.hasMoreTokens()) {
302: String tuple = tok.nextToken().trim();
303: int i = tuple.indexOf(' ');
304: String name = tuple.substring(i + 1, tuple.length());
305: String paramType = tuple.substring(0, i).trim();
306: PType type = getPType(paramType);
307: hparams.put(name, new Object[] { new Integer(idx),
308: new BasicParameterOperand(type, name) });
309: idx++;
310: if (type == PTypeSpaceMedor.PNAME) {
311: paramName2paramClass.put(name, getClass(paramType));
312: }
313: }
314: }
315: }
316:
317: protected void toHashtableVars(String stringToHash, String separator) {
318: hvars = new HashMap();
319: if (stringToHash != null) {
320: StringTokenizer tok = new StringTokenizer(stringToHash,
321: separator);
322: while (tok.hasMoreTokens()) {
323: String tuple = tok.nextToken().trim();
324: int i = tuple.indexOf(' ');
325: String type = tuple.substring(0, i);
326: hvars.put(tuple.substring(i + 1, tuple.length()), type);
327: }
328: }
329: }
330:
331: protected Class getClass(String classname) {
332: if (classLoader != null) {
333: try {
334: return classLoader.loadClass(classname);
335: } catch (ClassNotFoundException e) {
336: try {
337: return classLoader.loadClass(qd.candidateClass
338: .getPackage().getName()
339: + "." + classname);
340: } catch (ClassNotFoundException e2) {
341: return null;
342: }
343: }
344: } else {
345: return null;
346: }
347: }
348:
349: protected void flushCache(JDOPOManagerItf pm) {
350: if (!qd.ignoreCache || !pm.getIgnoreCache()) {
351: if (logger.isLoggable(BasicLevel.DEBUG)) {
352: logger.log(BasicLevel.DEBUG,
353: "Flush dirty instances of the working set ...");
354: }
355: try {
356: pm.getTransactionalPersistenceManager().flush(
357: (JDOTransactionItf) pm.currentTransaction(),
358: this );
359: } catch (PersistenceException e) {
360: throw new JDOException(
361: "Impossible to use the cache into a "
362: + "query: Error during the flushing of data on the support",
363: e);
364: }
365: }
366: }
367:
368: }
|