KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > speedo > query > lib > SpeedoCompiledQuery


1 /**
2  * Speedo: an implementation of JDO compliant personality on top of JORM generic
3  * I/O sub-system.
4  * Copyright (C) 2001-2004 France Telecom R&D
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  *
21  *
22  * Contact: speedo@objectweb.org
23  *
24  * Authors: S. Chassande-Barrioz
25  *
26  */

27
28 package org.objectweb.speedo.query.lib;
29
30 import java.io.CharArrayReader JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.Collection JavaDoc;
33 import java.util.Collections JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.Map JavaDoc;
37 import java.util.StringTokenizer JavaDoc;
38
39 import javax.jdo.JDOException;
40 import javax.jdo.JDOUserException;
41
42 import org.objectweb.jorm.api.PClassMapping;
43 import org.objectweb.jorm.api.PException;
44 import org.objectweb.jorm.api.PMapper;
45 import org.objectweb.jorm.lib.JormPathHelper;
46 import org.objectweb.jorm.metainfo.api.Manager;
47 import org.objectweb.jorm.naming.api.PName;
48 import org.objectweb.jorm.type.api.PType;
49 import org.objectweb.jorm.type.api.PTypeSpace;
50 import org.objectweb.medor.api.EvaluationException;
51 import org.objectweb.medor.api.MedorException;
52 import org.objectweb.medor.eval.lib.MedorEvaluator;
53 import org.objectweb.medor.eval.prefetch.api.PrefetchBufferFactory;
54 import org.objectweb.medor.expression.api.Expression;
55 import org.objectweb.medor.expression.api.ExpressionException;
56 import org.objectweb.medor.expression.api.Operand;
57 import org.objectweb.medor.expression.api.Operator;
58 import org.objectweb.medor.expression.api.ParameterOperand;
59 import org.objectweb.medor.expression.lib.And;
60 import org.objectweb.medor.expression.lib.BasicParameterOperand;
61 import org.objectweb.medor.expression.lib.ConditionalAnd;
62 import org.objectweb.medor.expression.lib.Equal;
63 import org.objectweb.medor.filter.api.FieldOperand;
64 import org.objectweb.medor.optim.api.QueryTransformer;
65 import org.objectweb.medor.optim.jorm.Jorm2Rdb;
66 import org.objectweb.medor.optim.lib.BasicQueryRewriter;
67 import org.objectweb.medor.optim.lib.FlattenQueryTreeRule;
68 import org.objectweb.medor.optim.lib.IndexesGenerator;
69 import org.objectweb.medor.optim.lib.PushNotInExpressionRule;
70 import org.objectweb.medor.query.api.OrderField;
71 import org.objectweb.medor.query.api.QueryTree;
72 import org.objectweb.medor.query.api.QueryTreeField;
73 import org.objectweb.medor.query.jorm.api.JormExtent;
74 import org.objectweb.medor.query.jorm.lib.JormQueryTreeHelper;
75 import org.objectweb.medor.query.jorm.lib.QueryBuilder;
76 import org.objectweb.medor.query.lib.BasicOrderField;
77 import org.objectweb.medor.query.lib.QueryTreePrinter;
78 import org.objectweb.medor.query.lib.SelectProject;
79 import org.objectweb.medor.tuple.api.TupleCollection;
80 import org.objectweb.medor.type.lib.PTypeSpaceMedor;
81 import org.objectweb.medor.type.lib.QType;
82 import org.objectweb.perseus.cache.api.UnFixProtocolException;
83 import org.objectweb.perseus.cache.replacement.api.ReplaceableCacheEntry;
84 import org.objectweb.perseus.persistence.api.PersistenceException;
85 import org.objectweb.perseus.persistence.api.State;
86 import org.objectweb.perseus.persistence.api.StateFilter;
87 import org.objectweb.speedo.api.SpeedoException;
88 import org.objectweb.speedo.mapper.api.JormFactory;
89 import org.objectweb.speedo.mapper.lib.DelegatePMapper;
90 import org.objectweb.speedo.mim.api.SpeedoHome;
91 import org.objectweb.speedo.mim.api.SpeedoProxy;
92 import org.objectweb.speedo.pm.api.ProxyManager;
93 import org.objectweb.speedo.query.api.CompiledQuery;
94 import org.objectweb.speedo.query.api.QueryDefinition;
95 import org.objectweb.speedo.query.parser.ASTSpeedoQL;
96 import org.objectweb.speedo.query.parser.ParseException;
97 import org.objectweb.speedo.query.parser.SelectGroupByVisitor;
98 import org.objectweb.speedo.query.parser.SimpleNode;
99 import org.objectweb.speedo.query.parser.SpeedoQL;
100 import org.objectweb.speedo.query.parser.SpeedoQLQueryFilterVisitor;
101 import org.objectweb.speedo.query.parser.SpeedoQLVariableVisitor;
102 import org.objectweb.speedo.usercache.api.UserCache;
103 import org.objectweb.speedo.usercache.lib.UserCacheKey;
104 import org.objectweb.speedo.workingset.api.Transaction;
105 import org.objectweb.util.monolog.api.BasicLevel;
106 import org.objectweb.util.monolog.api.Logger;
107
108 /**
109  * SpeedoCompiledQuery object represents a query. This object is created
110  * when a new query is created, and can be used several times. A list of
111  * SpeedoCompiledQuery is managed with a SpeedoQueryManager object.
112  * When a user creates a new JDO Query object (SpeedoQuery), a
113  * SpeedoCompiledQuery object is associated to the SpeedoQuery object which is
114  * used to delegate some methods.
115  */

116 public class SpeedoCompiledQuery
117         implements CompiledQuery, StateFilter, ReplaceableCacheEntry {
118
119     private short status;
120     private ClassLoader JavaDoc classLoader;
121
122     /**
123      * Fields from javax.jdo.Query
124      */

125     private QueryDefinitionImpl qd = null;
126
127     /**
128      * vparams, hparams and hvars are internal objects to manipulate the list
129      * of parameters, and the list of variables.
130      */

131     private Map JavaDoc hparams = null;
132     private Map JavaDoc paramName2paramClass = null;
133     private Map JavaDoc hvars = null;
134     private QueryEvalContext[] qecs = null;
135     private Class JavaDoc[] selectedFieldTypes = null;
136
137     /**
138      * The query tree which is the result from the parsing of the given filter
139      */

140     //private QueryTree qt = null;
141

142     private Collection JavaDoc pncParams = null;
143     /**
144      * Logger for monolog
145      */

146     private Logger logger = null;
147     private Logger varParserlogger = null;
148     private Logger filterParserLogger = null;
149
150     private DelegatePMapper mapper = null;
151     private JormFactory jf;
152     private PrefetchBufferFactory prefetchBufferFactory;
153     private UserCache userCache = null;
154     private Operand[] userCacheIndexes = null;
155
156
157     private long age = 0;
158     private int fixCount = 0;
159
160
161     public void init(Logger l,
162                      Logger logParserVar,
163                      Logger logParserFil,
164                      PMapper m,
165                      PrefetchBufferFactory pbf,
166                      JormFactory _jf) {
167         logger = l;
168         varParserlogger = logParserVar;
169         filterParserLogger = logParserFil;
170         mapper = new DelegatePMapper(m);
171         setJormFactory(_jf);
172         this.prefetchBufferFactory = pbf;
173     }
174
175     public PMapper getMapper() {
176         return mapper;
177     }
178
179     public void setMapper(PMapper m) {
180         mapper = new DelegatePMapper(m);
181         if (jf != null) {
182             mapper.setJormFactory(jf);
183         }
184     }
185
186     public void setJormFactory(JormFactory jf) {
187         this.jf = jf;
188         if (mapper != null) {
189             mapper.setJormFactory(jf);
190         }
191     }
192
193     public Logger getLogger() {
194         return logger;
195     }
196
197     public QueryEvalContext[] getQueryEvalContext() {
198         return qecs;
199     }
200
201     public PrefetchBufferFactory getPrefetchBufferFactory() {
202         return prefetchBufferFactory;
203     }
204
205     public boolean isPrefetchResult() {
206         return qd.withPrefetch;
207     }
208
209     public void defineQuery(QueryDefinition _qd) {
210         this.qd = new QueryDefinitionImpl(_qd);
211         classLoader = _qd.getCandidateClass().getClassLoader();
212         if (classLoader == null) {
213             classLoader = getClass().getClassLoader();
214             if (classLoader == null) {
215                 classLoader = ClassLoader.getSystemClassLoader();
216                 logger.log(BasicLevel.DEBUG, "The system classLoader of the " +
217                         "class is assigned to the query: " + classLoader);
218             } else {
219                 logger.log(BasicLevel.DEBUG, "The classLoader of Speedo is" +
220                         " assigned the query: " + classLoader);
221             }
222         } else {
223             logger.log(BasicLevel.DEBUG, "The classLoader of the class is " +
224                     "assigned to the query: " + classLoader);
225         }
226         mapper.setClassLoader(classLoader);
227         status = DEFINED;
228     }
229
230     // IMPLEMENTATION OF ReplaceableCacheEntry INTERFACE //
231
//---------------------------------------------------//
232
public long getCeAge() {
233         return age;
234     }
235
236     public void setCeAge(long _age) {
237         this.age = _age;
238     }
239
240     public void fixCe() {
241         fixCount++;
242     }
243
244     public void unfixCe() throws UnFixProtocolException {
245         fixCount--;
246     }
247
248     public int getCeFixCount() {
249         return fixCount;
250     }
251
252     public Object JavaDoc getCeObject() {
253         return this;
254     }
255
256     public Object JavaDoc getCeIdentifier() {
257         return qd;
258     }
259
260     // IMPLEMENTATION OF CompiledQuery INTERFACE //
261
//-------------------------------------------//
262
public synchronized QueryDefinition getDefinition() {
263         switch(status) {
264         case DEFINED:
265         case COMPILED:
266             return qd;
267         case UNDEFINED:
268         default:
269             return null;
270         }
271     }
272
273     /**
274      * compile the current SpeedoCompiledQuery.
275      * The query is prepared to be executed.
276      * The PersistenceManager is set (even if there was a previous definition
277      * of a PersistenceManager.
278      */

279     public synchronized void compile() throws SpeedoException, MedorException, ExpressionException {
280         if (status == UNDEFINED)
281             throw new SpeedoException("Impossible to compile an undefined query");
282         if (status == COMPILED)
283             return;
284         long timeToCompile = System.currentTimeMillis();
285         boolean debug = logger.isLoggable(BasicLevel.DEBUG);
286         // create a speedoQL object with a filter string
287
String JavaDoc filter = qd.filter;
288         filter = '(' + filter + ')';
289         // create representations of the parameters list and the variable
290
// list
291
toHashtableParams(qd.parameters, ";,");
292         toHashtableVars(qd.variables, ";,");
293         Manager miManager = mapper.getMetaInfoManager();
294         if (miManager == null)
295             throw new SpeedoException(
296                     "A non null Meta information manager is needed");
297         try {
298             jf.getPClassMapping(
299                     qd.candidateClass.getName(),
300                     classLoader);
301         } catch (Exception JavaDoc e) {
302             throw new SpeedoException(e);
303         }
304         SimpleNode node = null;
305         try {
306             node = new SpeedoQL(new CharArrayReader JavaDoc(filter.toCharArray())).SpeedoQL();
307         } catch (ParseException e) {
308             throw new SpeedoException(
309                     "Impossible to parse the filter and to create AST", e);
310         }
311         SpeedoQLVariableVisitor sqvv = new SpeedoQLVariableVisitor(
312                 node, miManager, varParserlogger, hparams, hvars, qd.order,
313                 qd.candidateClass.getName(), qd.includeSubClasses);
314         // start the variable visitor to catch all variables an build a
315
// first tree of them without collection navigation
316
Map JavaDoc fields = sqvv.getFields();
317         QueryBuilder qb = sqvv.getQueryBuilder();
318         QueryTree qt = sqvv.getQueryTree();
319
320         SelectProject sp = new SelectProject("");
321         if (!filter.equals("(true)") && !filter.equals("true")) {
322             //Ther is a filter and potentialy collection navigation
323
if (debug) {
324                 logger.log(BasicLevel.DEBUG, "filter = " + qd.filter);
325             }
326             // start the query filter visitor, to build and expression tree of
327
// the filter expression
328
SpeedoQLQueryFilterVisitor sqfv = new SpeedoQLQueryFilterVisitor(
329                     fields, sp, (ASTSpeedoQL) node,
330                     filterParserLogger, hparams, hvars,
331                     qd.candidateClass,
332                     qb, jf);
333             sp.setQueryFilter(sqfv.getQueryFilter());
334         }
335         assignMapper(sp);
336         assignMapper(qt);
337
338         QueryEvalContext qec = new QueryEvalContext(sp, this);
339         
340         SelectGroupByVisitor sgv = new SelectGroupByVisitor(
341                 sp, qt, mapper, sqvv, qd, qec, classLoader);
342         
343         sgv.visit(qd);
344         selectedFieldTypes = sgv.getSelectFieldTypes();
345         assignMapper(qec.query);
346         
347         //Specify the ordering
348
if (qd.order != null && qd.order.size() > 0) {
349             OrderField[] ofs = new OrderField[qd.order.size()];
350             for(int i=0; i<ofs.length; i++) {
351                 String JavaDoc o = (String JavaDoc) qd.order.get(i);
352                 int idx = o.indexOf(' ');
353                 boolean desc = false;
354                 if (idx != -1) {
355                     desc = o.substring(idx + 1).trim().equals("descending");
356                     o = o.substring(0, idx);
357                 }
358                 o = "this." + o;
359                 ofs[i] = new BasicOrderField((QueryTreeField)
360                     qt.getTupleStructure().getField(o), desc);
361             }
362             sp.setOrderBy(ofs);
363         }
364
365         logger.log(BasicLevel.INFO, "QueryTree built");
366         if (debug) {
367             QueryTreePrinter.printQueryTree(qec.query, logger);
368         }
369         //check for the use of the userCache
370
if (qd.result == null && qd.variables == null) {
371             //no variable used and the result is the candidate class
372
Map JavaDoc field2value = new HashMap JavaDoc();
373             if (getFieldComparaison(sp.getQueryFilter(), field2value)) {
374                 SpeedoHome sh = null;
375                 try {
376                     sh = (SpeedoHome) jf.getPClassMapping(
377                             qd.candidateClass.getName(),
378                             classLoader);
379                 } catch (PException e) {
380                     //never happen
381
}
382                 userCache = sh.getUserCache(field2value.keySet());
383                 if (userCache != null) {
384                     userCacheIndexes = new Operand[field2value.size()];
385                     String JavaDoc[] ifs = userCache.getIndexFieldNames();
386                     for (int i = 0; i < ifs.length; i++) {
387                         userCacheIndexes[i] = (Operand) field2value.get(ifs[i]);
388                     }
389                 }
390             }
391             
392         }
393         
394         // Optimize the queryTree
395
optimize(qec, debug);
396         
397         // Creates an evaluator associated to the QueryTree
398
qec.evaluator = new MedorEvaluator(qec.query, 0);
399         
400         qecs = new QueryEvalContext[] {qec};
401         timeToCompile = System.currentTimeMillis() - timeToCompile;
402         status = COMPILED;
403         logger.log(BasicLevel.INFO, "Query compiled in " + timeToCompile + "ms");
404     }
405
406     private boolean getFieldComparaison(Expression e, Map JavaDoc field2value) {
407         if (e instanceof And || e instanceof ConditionalAnd) {
408             return getFieldComparaison(((Operator) e).getExpression(0), field2value)
409                 && getFieldComparaison(((Operator) e).getExpression(1), field2value);
410         } else if (e instanceof Equal){
411             Expression tmpe = ((Operator) e).getExpression(0);
412             if (!(tmpe instanceof Operand)) {
413                 return false;
414             }
415             Operand op0 = (Operand) tmpe;
416             tmpe = ((Operator) e).getExpression(1);
417             if (!(tmpe instanceof Operand)) {
418                 return false;
419             }
420             Operand op1 = (Operand) tmpe;
421             //Equal between two operand
422
if (op0 instanceof FieldOperand) {
423             } else if (op1 instanceof FieldOperand) {
424                 //revert if op1 is
425
Operand o = op0;
426                 op0 = op1;
427                 op1 = o;
428             } else {
429                 return false;
430             }
431             //op0 is a field operand
432
if (op1 instanceof FieldOperand) {
433                 return false;
434             }
435             // parameter operand or simple operand (constant)
436
String JavaDoc fieldName = ((FieldOperand) op0).getField().getName();
437             if (fieldName.indexOf('.') != -1) { // short or long navigation path
438
if (fieldName.startsWith("this.")) { //path starts with "this."
439
fieldName = fieldName.substring(5); //remove "this."
440
}
441                 if (fieldName.indexOf('.') != -1) { //long navigation path
442
return false;
443                 }
444             }
445             field2value.put(fieldName, op1);
446             return true;
447         }
448         return false;
449     }
450     
451     
452     /**
453      * Assign mappers and project and project name on the JormExtent nodes
454      * include in a QueryTree.
455      * @throws SpeedoException
456      */

457     private void assignMapper(QueryTree qt)throws SpeedoException {
458         //
459
Collection JavaDoc extents = JormQueryTreeHelper.getJormExtents(qt);
460         boolean debug = logger.isLoggable(BasicLevel.DEBUG);
461         if (debug) {
462             logger.log(BasicLevel.DEBUG, "Extent nodes: " + extents.size());
463         }
464         for (Iterator JavaDoc it = extents.iterator(); it.hasNext();) {
465             JormExtent je = (JormExtent) it.next();
466             try {
467                 PClassMapping pcm = jf.getPClassMapping(
468                         JormPathHelper.getOriginClass(je.getJormName()),
469                         classLoader);
470                 if (debug) {
471                     logger.log(BasicLevel.DEBUG,
472                             "JormExtent: " + je + " / pcm=" + pcm);
473                 }
474                 je.setPMapper(pcm.getPMapper(), pcm.getProjectName());
475             } catch (PException e) {
476                 throw new SpeedoException(
477                         "Error while fetching PClassPMapping of the class "
478                         + je.getJormName(), e);
479             }
480         }
481     }
482
483     private void optimize(QueryEvalContext pqc, boolean debug)
484         throws MedorException, ExpressionException {
485         ArrayList JavaDoc rules = new ArrayList JavaDoc();
486         rules.add(new PushNotInExpressionRule());
487         rules.add(new FlattenQueryTreeRule());
488         //TODO: remove the dependency to JormFlatten2Rdb
489
rules.add(new Jorm2Rdb());
490         QueryTransformer queryTransformer = new BasicQueryRewriter(rules);
491         IndexesGenerator indexesGenerator = new IndexesGenerator();
492         try {
493             pqc.query = queryTransformer.transform(pqc.query);
494             if (debug) {
495                 logger.log(BasicLevel.DEBUG, "Query optimized");
496                 QueryTreePrinter.printQueryTree(pqc.query, logger);
497             }
498             pqc.query = indexesGenerator.transform(pqc.query);
499         } catch (Exception JavaDoc e) {
500             throw new MedorException("Impossible to optimize the query", e);
501         }
502
503         pncParams = JormQueryTreeHelper.getRequiredPNameManagers(pqc.query);
504         for (Iterator JavaDoc it = pncParams.iterator(); it.hasNext();) {
505             ParameterOperand po = (ParameterOperand) it.next();
506             String JavaDoc name = po.getName();
507             if (debug) {
508                 logger.log(BasicLevel.DEBUG, "ParameterOperand " + name + " is expected.");
509             }
510             po.setValue(JormPathHelper.getPNameCoder(name, mapper));
511         }
512     }
513
514
515     /**
516      * evaluate the query with a single parameter which is a array of object
517      * parameters.
518      * @param pm the persistence manager object
519      * @param a the array parameter of the query
520      * @return a Collection of result objects
521      * @throws org.objectweb.medor.api.EvaluationException
522      * @throws org.objectweb.medor.api.MedorException
523      */

524     public Object JavaDoc execute(Object JavaDoc[] a, ProxyManager pm, QueryDefinition userqd)
525             throws SpeedoException, MedorException, ExpressionException {
526         if (status != COMPILED)
527             throw new EvaluationException(
528                     "Impossible to execute a query if it has not been defined and compiled before");
529         ParameterOperand[] pos = null;
530         if (a != null) {
531             pos = new ParameterOperand[a.length + pncParams.size()];
532             for(Iterator JavaDoc it = hparams.values().iterator(); it.hasNext();) {
533                 Object JavaDoc[] o = (Object JavaDoc[]) it.next();
534                 int idx = ((Integer JavaDoc) o[0]).intValue();
535                 pos[idx] = new BasicParameterOperand(
536                     (BasicParameterOperand) o[1]);
537                 treatParameter(pos[idx], a[idx]);
538             }
539         } else {
540             pos = new ParameterOperand[pncParams.size()];
541         }
542         if (pncParams.size() >0) {
543             int i = (a == null ? 0 : a.length);
544             for (Iterator JavaDoc it = pncParams.iterator(); it.hasNext(); i++) {
545                 pos[i++] = (ParameterOperand) it.next();
546             }
547         }
548         return executeQT(pm, pos, userqd);
549     }
550
551
552     /**
553      * evaluate the query with a single parameter which is a Map of object parameters.
554      * @param pm the persistence manager object
555      * @param m the map parameter of the query
556      * @return a Collection of result objects
557      * @throws org.objectweb.medor.api.EvaluationException
558      * @throws org.objectweb.medor.api.MedorException
559      */

560     public Object JavaDoc execute(Map JavaDoc m, ProxyManager pm, QueryDefinition userqd)
561             throws SpeedoException, MedorException, ExpressionException {
562         if (status != COMPILED)
563             throw new EvaluationException(
564                     "Impossible to execute a query if it has not been defined and compiled before");
565         ParameterOperand[] pos =
566                 new BasicParameterOperand[m.size() + pncParams.size()];
567         for(Iterator JavaDoc it = hparams.values().iterator(); it.hasNext();) {
568             Object JavaDoc[] o = (Object JavaDoc[]) it.next();
569             int idx = ((Integer JavaDoc) o[0]).intValue();
570             pos[idx] = new BasicParameterOperand(
571                 (BasicParameterOperand) o[1]);
572             treatParameter(pos[idx], m.get(pos[idx].getName()));
573             }
574         if (pncParams.size() >0) {
575             int i = (m == null ? 0 : m.size());
576             for (Iterator JavaDoc it = pncParams.iterator(); it.hasNext(); i++) {
577                 pos[i++] = (ParameterOperand) it.next();
578             }
579         }
580         return executeQT(pm, pos, userqd);
581     }
582
583     private void treatParameter(ParameterOperand po, Object JavaDoc value)
584         throws SpeedoException, ExpressionException {
585         Object JavaDoc val = value;
586         if (po.getType().getTypeCode() == QType.TYPECODE_PNAME) {
587             //Assign the pname of the parameter
588
if (val == null) {
589                 try {
590                     val =
591                         jf.getPClassMapping(
592                         (Class JavaDoc) paramName2paramClass.get(po.getName()))
593                         .getPBinder().getNull();
594                 } catch (Exception JavaDoc e) {
595                     throw new SpeedoException(
596                         "Impossible to find the null PName of the parameter (name= "
597                         + po.getName()
598                         + " / type= " + po.getType().getJormName(),
599                         e);
600                 }
601             } else if (val instanceof SpeedoProxy) {
602                 val = ((SpeedoProxy) value).getPName();
603             } else {
604                 throw new JDOUserException("The parameter '"
605                     + po.getName()
606                     + "' must be a persistent object: " + val);
607             }
608         }
609         po.setValue(val);
610     }
611
612     public short getStatus() {
613         return status;
614     }
615
616     // Private Methods //
617
//-----------------//
618

619     /**
620      * Hash a String, and compute a Hashtable
621      * example:
622      * ("String name, Float salary, Employee boss", ",")
623      * keys | values
624      * ---------------------
625      * "name" | "String"
626      * "salary" | "Float"
627      * "boss" | "Employee"
628      *
629      * @param stringToHash the String to hash
630      * @param separator the separator to tokenize
631      */

632     private void toHashtableParams(String JavaDoc stringToHash, String JavaDoc separator) {
633         hparams = new HashMap JavaDoc();
634         paramName2paramClass = new HashMap JavaDoc();
635         if (stringToHash != null) {
636             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(stringToHash, separator);
637             int idx = 0;
638             while (tok.hasMoreTokens()) {
639                 String JavaDoc tuple = tok.nextToken().trim();
640                 int i = tuple.indexOf(' ');
641                 String JavaDoc name = tuple.substring(i + 1, tuple.length());
642                 String JavaDoc paramType = tuple.substring(0, i).trim();
643                 PType type = getPType(paramType);
644                 hparams.put(name, new Object JavaDoc[]{
645                     new Integer JavaDoc(idx),
646                     new BasicParameterOperand(type, name)});
647                 idx ++;
648                 if (type == PTypeSpaceMedor.PNAME) {
649                     paramName2paramClass.put(name, getClass(paramType));
650                 }
651             }
652         }
653     }
654
655     private void toHashtableVars(String JavaDoc stringToHash, String JavaDoc separator) {
656         hvars = new HashMap JavaDoc();
657         if (stringToHash != null) {
658             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(stringToHash, separator);
659             while (tok.hasMoreTokens()) {
660                 String JavaDoc tuple = tok.nextToken().trim();
661                 int i = tuple.indexOf(' ');
662                 String JavaDoc type = tuple.substring(0, i);
663                 hvars.put(tuple.substring(i + 1, tuple.length()), type);
664             }
665         }
666     }
667
668     private PType getPType(String JavaDoc name) {
669         if ("String".equals(name)) {
670             return PTypeSpace.STRING;
671         }
672         if ("Integer".equals(name)) {
673             return PTypeSpace.OBJINT;
674         }
675         for (int i = 0; i < PTypeSpace.PREDEFINEDPTYPES.length; i++) {
676             PType type = PTypeSpace.PREDEFINEDPTYPES[i];
677             if (type.getJavaName().equals(name)
678                 || type.getJormName().equals(name)) {
679                 return type;
680             }
681         }
682         if ("Collection".equals(name)
683                 || PTypeSpaceMedor.COLLECTION.getJavaName().equals(name)) {
684             return PTypeSpaceMedor.COLLECTION;
685         }
686         return PTypeSpaceMedor.PNAME;
687     }
688     private Class JavaDoc getClass(String JavaDoc classname) {
689         if (classLoader != null) {
690             try {
691                 return classLoader.loadClass(classname);
692             } catch (ClassNotFoundException JavaDoc e) {
693                 try {
694                     return classLoader.loadClass(
695                             qd.candidateClass.getPackage().getName() + "." + classname);
696                 } catch (ClassNotFoundException JavaDoc e2) {
697                     return null;
698                 }
699             }
700         } else {
701             return null;
702         }
703     }
704
705     /**
706      * executes a the current query, and returns a Collection of object.
707      * @param userqd is the user query definition. It contains the range values
708      * and some other values that can change from the original compiled query.
709      * @return a new Collection of objects.
710      * @throws org.objectweb.medor.api.EvaluationException
711      * @throws org.objectweb.medor.api.MedorException
712      */

713     private Object JavaDoc executeQT(ProxyManager pm, ParameterOperand[] pos, QueryDefinition userqd)
714         throws EvaluationException, MedorException, SpeedoException {
715         if (!qd.ignoreCache || !pm.getIgnoreCache()) {
716             if (logger.isLoggable(BasicLevel.DEBUG)) {
717                 logger.log(BasicLevel.DEBUG,
718                     "Flush dirty instances of the working set ...");
719             }
720             try {
721                 pm.getTransactionalPersistenceManager()
722                         .flush((Transaction) pm.currentTransaction(), this);
723             } catch (PersistenceException e) {
724                 throw new JDOException("Impossible to use the cache into a " +
725                         "query: Error during the flushing of data on the support", e);
726             }
727         }
728         if (userCache != null) { //the query matches to an unique index
729
Object JavaDoc key = null;
730             //building the key
731
if (userCacheIndexes.length == 1) {
732                 //Index is single
733
key = getValueFromOperand(userCacheIndexes[0], pos);
734             } else {
735                 //key is composite
736
key = new UserCacheKey(userCacheIndexes.length);
737                 for (int i = 0; i < userCacheIndexes.length; i++) {
738                     ((UserCacheKey) key).setPart(i,
739                             getValueFromOperand(userCacheIndexes[0], pos));
740                 }
741             }
742             // search in the user cache
743
key = userCache.lookup(key);
744             if (key != null) {
745                 try {
746                     if (key instanceof PName) { //the cache contains PName
747
key = pm.getObjectById(key, false);
748                     }
749                     if (qd.unique) {
750                         return key;
751                     } else {
752                         return Collections.singletonList(key);
753                     }
754                 } catch (JDOException e) {
755                     logger.log(BasicLevel.WARN,
756                             "User cache is not up to date:", e);
757                 }
758             }
759         }
760         
761         Object JavaDoc connection = ((Transaction) pm.currentTransaction())
762                 .getConnectionHolder();
763         TupleCollection queryResult = null;
764         if (qecs.length == 1) {
765             //optimization: avoid to use an intermediate class
766
queryResult = qecs[0].eval(pm, pos, connection, userqd);
767             if (queryResult == null || queryResult.isEmpty()) {
768                 logger.log(BasicLevel.INFO,
769                         "Be careful, the result is empty");
770                 if (queryResult != null) {
771                     queryResult.close();
772                 }
773                 QueryResultCommon.closeConnection(connection);
774                 if (qd.unique) {
775                     return null;
776                 } else {
777                     return Collections.EMPTY_SET;
778                 }
779             }
780         } else {
781             //Use a multiplex of query
782
queryResult = new QueriesUnion(pos, pm, connection, qecs, userqd);
783         }
784         if (qd.unique) {
785             return new QueryResultUnique(
786                     queryResult,
787                     pm,
788                     new Object JavaDoc[]{connection},
789                     qd.resultClass,
790                     selectedFieldTypes,
791                     qecs.length == 1,
792                     logger).getResult();
793         } else {
794             return new QueryResultList(
795                     queryResult,
796                     pm,
797                     new Object JavaDoc[]{connection},
798                     qd.resultClass,
799                     selectedFieldTypes,
800                     qecs.length == 1,
801                     logger);
802         }
803     }
804
805     private Object JavaDoc getValueFromOperand(Operand op, ParameterOperand[] pos) {
806         if (op instanceof ParameterOperand) {
807             String JavaDoc param = ((ParameterOperand) op).getName();
808             for (int i = 0; i < pos.length; i++) {
809                 if (pos[i].getName().equals(param)) {
810                     return pos[i].getObject();
811                 }
812             }
813             return null;
814         } else {
815             return op.getObject();
816         }
817     }
818     
819     // IMPLEMENTATION OF THE CacheEntryFilter INTERFACE //
820
//--------------------------------------------------//
821

822     public boolean accept(State ce) {
823         if (logger.isLoggable(BasicLevel.DEBUG)) {
824             logger.log(BasicLevel.DEBUG,
825                 "Flush dirty instance of the working state, identifier: "
826                     + ce.getCacheEntry().getCeIdentifier());
827         }
828         return true;
829     }
830
831
832 }
Popular Tags