001: /**
002: * Speedo: an implementation of JDO compliant personality on top of JORM generic
003: * I/O sub-system.
004: * Copyright (C) 2001-2004 France Telecom R&D
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: *
021: *
022: * Contact: speedo@objectweb.org
023: *
024: * Authors: S.Chassande-Barrioz.
025: *
026: */package org.objectweb.speedo.query.jdo;
027:
028: import org.objectweb.jorm.naming.api.PName;
029: import org.objectweb.medor.api.MedorException;
030: import org.objectweb.medor.expression.api.ExpressionException;
031: import org.objectweb.speedo.api.ExceptionHelper;
032: import org.objectweb.speedo.api.SpeedoException;
033: import org.objectweb.speedo.api.SpeedoRuntimeException;
034: import org.objectweb.speedo.mim.api.PersistentObjectItf;
035: import org.objectweb.speedo.mim.api.StateItf;
036: import org.objectweb.speedo.pm.jdo.api.JDOPOManagerItf;
037: import org.objectweb.speedo.query.api.CompiledQuery;
038: import org.objectweb.speedo.query.api.QueryManager;
039: import org.objectweb.util.monolog.api.BasicLevel;
040: import org.objectweb.util.monolog.api.Logger;
041:
042: import java.util.ArrayList;
043: import java.util.Collection;
044: import java.util.HashMap;
045: import java.util.Iterator;
046: import java.util.List;
047: import java.util.Map;
048: import java.util.StringTokenizer;
049: import java.util.Vector;
050:
051: import javax.jdo.Extent;
052: import javax.jdo.FetchPlan;
053: import javax.jdo.JDOException;
054: import javax.jdo.JDOFatalUserException;
055: import javax.jdo.JDOUserException;
056: import javax.jdo.PersistenceManager;
057: import javax.jdo.Query;
058: import javax.jdo.listener.DeleteCallback;
059:
060: /**
061: * SpeedoQuery is the basic implementation of the javax.jdo.Query interface.
062: * This class is just a wrapper to a SpeedoCompiledQuery object which is a
063: * reused object.
064: *
065: * @author S. Chassande-Barrioz
066: */
067: public class JDOQuery extends JDOQueryDefinitionImpl implements Query {
068:
069: /**
070: *
071: */
072: private static final long serialVersionUID = 3412369898739619393L;
073:
074: /**
075: * The queryManager object is used to create or return a CompiledQuery
076: * object.
077: */
078: private QueryManager queryManager = null;
079:
080: /**
081: * Logger for monolog.
082: */
083: private Logger logger = null;
084:
085: private boolean hasChanged = true;
086:
087: /**
088: * PersistenceManager which manages this query.
089: */
090: private JDOPOManagerItf pm;
091:
092: private List results;
093:
094: /**
095: * sQueryCompiler is the query, this object can compile and execute the
096: * query. This object is reused in the past, or future.
097: */
098: private CompiledQuery qc = null;
099:
100: /**
101: * The fetch plan.
102: * When a Query is retrieved from a PersistenceManager, its FetchPlan is initialized to the same settings
103: * as that of the PersistenceManager.
104: * Subsequent modifications of the Query's FetchPlan are not reflected
105: * in the FetchPlan of the PersistenceManager.
106: */
107: private FetchPlan fetchPlan;
108:
109: public JDOQuery() {
110: super ();
111: results = new ArrayList(1);
112: }
113:
114: public void setLogger(Logger logger) {
115: this .logger = logger;
116: }
117:
118: public QueryManager getQueryManager() {
119: return queryManager;
120: }
121:
122: public void setQueryManager(QueryManager aqm) {
123: queryManager = aqm;
124: }
125:
126: public CompiledQuery getQueryCompiler() {
127: return qc;
128: }
129:
130: public void setQueryCompiler(CompiledQuery aqc) {
131: qc = aqc;
132: }
133:
134: public void setPOManager(JDOPOManagerItf apm) {
135: pm = apm;
136: }
137:
138: public void defineWith(String query) {
139: //TODO: support query definition a single string
140: }
141:
142: // IMPLEMENTATION OF THE Query INTERFACE //
143: //---------------------------------------//
144:
145: public void defineWith(JDOQueryDefinitionImpl qd) {
146: super .defineWith(qd);
147: hasChanged = true;
148: }
149:
150: /**
151: * Set the class of the candidate instances of the query.
152: * <P>The class specifies the class
153: * of the candidates of the query. Elements of the candidate collection
154: * that are of the specified class are filtered before being
155: * put into the result Set.
156: * @param cls the Class of the candidate instances.
157: */
158: public void setClass(Class cls) {
159: assertPMIsOpen();
160: assertModifiable();
161: if (candidateClass != null)
162: hasChanged = true;
163: candidateClass = cls;
164: assertCandidateClass();
165: }
166:
167: /**
168: * Set the candidate Extent to query.
169: * @param pcs the Candidate Extent.
170: */
171: public void setCandidates(Extent pcs) {
172: assertPMIsOpen();
173: if (extentClass != null)
174: hasChanged = true;
175: extentClass = pcs;
176: assertExtentClass();
177: }
178:
179: /**
180: * Set the candidate Set to query.
181: * @param pcs the Candidate collection.
182: */
183: public void setCandidates(Collection pcs) {
184: assertPMIsOpen();
185: assertModifiable();
186: if (candidateInstances != null)
187: hasChanged = true;
188: candidateInstances = pcs;
189: assertCandidateInstances();
190: }
191:
192: /**
193: * Set the filter for the query.
194: * <P>The filter specification is a String containing a boolean
195: * expression that is to be evaluated for each of the instances
196: * in the candidate collection. If the filter is not specified,
197: * then it defaults to "true", which has the effect of filtering
198: * the input Set only for class type.
199: * <P>An element of the candidate collection is returned in the result if:
200: * <ul><li>it is assignment compatible to the candidate Class of the Query; and
201: * <li>for all variables there exists a value for which the filter
202: * expression evaluates to true.
203: * </ul>
204: * <P>The user may denote uniqueness in the filter expression by
205: * explicitly declaring an expression (for example, e1 != e2).
206: * <P>Rules for constructing valid expressions follow the Java
207: * language, except for these differences:
208: * <ul>
209: * <li>Equality and ordering comparisons between primitives and instances
210: * of wrapper classes are valid.
211: * <li>Equality and ordering comparisons of Date fields and Date
212: * parameters are valid.
213: * <li>White space (non-printing characters space, tab, carriage
214: * return, and line feed) is a separator and is otherwise ignored.
215: * <li>The assignment operators =, +=, etc. and pre- and post-increment
216: * and -decrement are not supported. Therefore, there are no side
217: * effects from evaluation of any expressions.
218: * <li>Methods, including object construction, are not supported, except
219: * for Set.contains(Object o), Set.isEmpty(),
220: * String.startsWith (String s), and String.endsWith (String e).
221: * Implementations might choose to support non-mutating method
222: * calls as non-standard extensions.
223: * <li>Navigation through a null-valued field, which would throw
224: * NullPointerException, is treated as if the filter expression
225: * returned false for the evaluation of the current set of variable
226: * values. Other values for variables might still qualify the candidate
227: * instance for inclusion in the result set.
228: * <li>Navigation through multi-valued fields (Set types) is
229: * specified using a variable declaration and the
230: * Set.contains(Object o) method.
231: * </ul>
232: * <P>Identifiers in the expression are considered to be in the name
233: * space of the specified class, with the addition of declared imports,
234: * parameters and variables. As in the Java language, this is a reserved
235: * word which means the element of the collection being evaluated.
236: * <P>Navigation through single-valued fields is specified by the Java
237: * language syntax of field_name.field_name....field_name.
238: * <P>A JDO implementation is allowed to reorder the filter expression
239: * for optimization purposes.
240: * @param f the query filter.
241: */
242: public void setFilter(String f) {
243: assertPMIsOpen();
244: assertModifiable();
245: if (f == null || f.length() == 0) {
246: filter = "true";
247: } else {
248: filter = "(" + f + ")";
249: hasChanged = true;
250: }
251: }
252:
253: /**
254: * Set the import statements to be used to identify the fully qualified name of
255: * variables or parameters. Parameters and unbound variables might
256: * come from a different class from the candidate class, and the names
257: * need to be declared in an import statement to eliminate ambiguity.
258: * Import statements are specified as a String with semicolon-separated
259: * statements.
260: * <P>The String parameter to this method follows the syntax of the
261: * import statement of the Java language.
262: * @param imports import statements separated by semicolons.
263: */
264: public void declareImports(String imports) {
265: assertPMIsOpen();
266: assertModifiable();
267: if (importStatements != null)
268: hasChanged = true;
269: StringTokenizer tok = new StringTokenizer(imports, ";");
270: importStatements = new Vector();
271: while (tok.hasMoreTokens())
272: importStatements.add(tok.nextToken().trim());
273: }
274:
275: /**
276: * Declare the list of parameters query execution.
277: * The parameter declaration is a String containing one or more query
278: * parameter declarations separated with commas. Each parameter named
279: * in the parameter declaration must be bound to a value when
280: * the query is executed.
281: * <P>The String parameter to this method follows the syntax for formal
282: * parameters in the Java language.
283: * @param parameters the list of parameters separated by commas.
284: */
285: public void declareParameters(String parameters) {
286: assertPMIsOpen();
287: assertModifiable();
288: if (this .parameters != null) {
289: hasChanged = true;
290: }
291: this .parameters = parameters;
292: assertParameters();
293: }
294:
295: /**
296: * Declare the unbound variables to be used in the query. Variables
297: * might be used in the filter, and these variables must be declared
298: * with their type. The unbound variable declaration is a String
299: * containing one or more unbound variable declarations separated
300: * with semicolons. It follows the syntax for local variables in
301: * the Java language.
302: * @param variables the variables separated by semicolons.
303: */
304: public void declareVariables(String variables) {
305: assertPMIsOpen();
306: assertModifiable();
307: if (this .variables != null)
308: hasChanged = true;
309: this .variables = variables;
310: assertVariables();
311: }
312:
313: /**
314: * Set the ordering specification for the result Set. The
315: * ordering specification is a String containing one or more ordering
316: * declarations separated by commas.
317: *
318: * <P>Each ordering declaration is the name of the field on which
319: * to order the results followed by one of the following words:
320: * "ascending" or "descending".
321: *
322: *<P>The field must be declared in the candidate class or must be
323: * a navigation expression starting with a field in the candidate class.
324: *
325: *<P>Valid field types are primitive types except boolean; wrapper types
326: * except Boolean; BigDecimal; BigInteger; String; and Date.
327: * @param ordering the ordering specification.
328: */
329: public void setOrdering(String ordering) {
330: assertPMIsOpen();
331: assertModifiable();
332: if (order != null)
333: hasChanged = true;
334: StringTokenizer tok = new StringTokenizer(ordering, ",");
335: order = new ArrayList();
336: while (tok.hasMoreTokens())
337: order.add(tok.nextToken().trim());
338: }
339:
340: /**
341: * Set the ignoreCache option. The default value for this option was
342: * set by the PersistenceManagerFactory or the PersistenceManager used
343: * to create this Query.
344: *
345: * The ignoreCache option setting specifies whether the query should execute
346: * entirely in the back end, instead of in the cache. If this flag is set
347: * to true, an implementation might be able to optimize the query
348: * execution by ignoring changed values in the cache. For optimistic
349: * transactions, this can dramatically improve query response times.
350: * @param ignoreCache the setting of the ignoreCache option.
351: */
352: public void setIgnoreCache(boolean ignoreCache) {
353: assertPMIsOpen();
354: assertModifiable();
355: this .ignoreCache = ignoreCache;
356: }
357:
358: /**
359: * Get the ignoreCache option setting.
360: * @return the ignoreCache option setting.
361: * @see #setIgnoreCache
362: */
363: public boolean getIgnoreCache() {
364: assertPMIsOpen();
365: return ignoreCache;
366: }
367:
368: public void setIncludeSubClasses(boolean val) {
369: assertModifiable();
370: hasChanged = true;
371: includeSubClasses = val;
372: }
373:
374: /**
375: * Verify the elements of the query and provide a hint to
376: * the query to prepare and optimize an execution plan.
377: */
378: public void compile() {
379: // build a CompiledQuery object with the current object.
380: // if the object already exists, it is returned
381: qc = queryManager.getQueryCompiler(this );
382:
383: // compile the CompiledQuery object
384: try {
385: qc.compile();
386: } catch (Exception e) {
387: throw new JDOException("Impossible to compile a query ", e);
388: }
389: hasChanged = false;
390: }
391:
392: private void treatSpeedoHints(Map parameterValues) {
393: String speedoHints = (String) parameterValues
394: .get("SPEEDO_HINTS");
395: if (speedoHints != null) {
396: treatSpeedoHints(speedoHints);
397: }
398: }
399:
400: private void treatSpeedoHints(Object[] parameterValues) {
401: StringTokenizer st = new StringTokenizer(parameters, ",", false);
402: int speedoHintsIndex = -1;
403: int tokenIndex = 0;
404: while (speedoHintsIndex < 0 && st.hasMoreTokens()) {
405: String token = st.nextToken();
406: if (token.indexOf("SPEEDO_HINTS") > -1) {
407: speedoHintsIndex = tokenIndex;
408: }
409: tokenIndex++;
410: }
411: if (speedoHintsIndex >= 0) {
412: treatSpeedoHints((String) parameterValues[speedoHintsIndex]);
413: }
414: }
415:
416: private void treatSpeedoHints(String speedoHints) {
417: StringTokenizer st = new StringTokenizer(speedoHints, ",",
418: false);
419: while (st.hasMoreTokens()) {
420: String token = st.nextToken();
421: if (token.equalsIgnoreCase("prefetch")) {
422: if (!withPrefetch) {
423: withPrefetch = true;
424: hasChanged = true;
425: }
426: } else if (token.equalsIgnoreCase("noprefetch")) {
427: if (withPrefetch) {
428: withPrefetch = false;
429: hasChanged = true;
430: }
431: //} else if (token.equalsIgnoreCase("list")) {
432:
433: }
434: }
435:
436: }
437:
438: /**
439: * Execute the query and return the filtered Set.
440: * @return the filtered Set.
441: * @see #executeWithArray(java.lang.Object[] parameters)
442: */
443: public Object execute() {
444: Object[] params = new Object[0];
445: beforeExecute(params);
446: try {
447: Object res = qc.execute(params, pm, this );
448: if (!unique) {
449: results.add(res);
450: }
451: return res;
452: } catch (JDOException e) {
453: throw e;
454: } catch (Exception e) {
455: logger.log(BasicLevel.ERROR, "execute failed", e);
456: throw new JDOException("Impossible to execute a query ", e);
457: }
458: }
459:
460: /**
461: * Execute the query and return the filtered Set.
462: * @return the filtered Set.
463: * @see #executeWithArray(java.lang.Object[] parameters)
464: * @param p1 the value of the first parameter declared.
465: */
466: public Object execute(Object p1) {
467: Object[] params = new Object[] { p1 };
468: beforeExecute(params);
469: try {
470: Object res = qc.execute(params, pm, this );
471: if (!unique) {
472: results.add(res);
473: }
474: return res;
475: } catch (JDOException e) {
476: throw e;
477: } catch (Exception e) {
478: logger.log(BasicLevel.ERROR, "execute failed", e);
479: throw new JDOException("Impossible to execute a query ", e);
480: }
481: }
482:
483: /**
484: * Execute the query and return the filtered Set.
485: * @return the filtered Set.
486: * @see #executeWithArray(java.lang.Object[] parameters)
487: * @param p1 the value of the first parameter declared.
488: * @param p2 the value of the second parameter declared.
489: */
490: public Object execute(Object p1, Object p2) {
491: Object[] params = new Object[] { p1, p2 };
492: beforeExecute(params);
493: try {
494: Object res = qc.execute(params, pm, this );
495: if (!unique) {
496: results.add(res);
497: }
498: return res;
499: } catch (JDOException e) {
500: throw e;
501: } catch (Exception e) {
502: logger.log(BasicLevel.ERROR, "execute failed", e);
503: throw new JDOException("Impossible to execute a query ", e);
504: }
505: }
506:
507: /**
508: * Execute the query and return the filtered Set.
509: * @return the filtered Set.
510: * @see #executeWithArray(java.lang.Object[] parameters)
511: * @param p1 the value of the first parameter declared.
512: * @param p2 the value of the second parameter declared.
513: * @param p3 the value of the third parameter declared.
514: */
515: public Object execute(Object p1, Object p2, Object p3) {
516: Object[] params = new Object[] { p1, p2, p3 };
517: beforeExecute(params);
518: try {
519: Object res = qc.execute(params, pm, this );
520: if (!unique) {
521: results.add(res);
522: }
523: return res;
524: } catch (JDOException e) {
525: throw e;
526: } catch (Exception e) {
527: logger.log(BasicLevel.ERROR, "execute failed", e);
528: throw new JDOException("Impossible to execute a query ", e);
529: }
530: }
531:
532: /**
533: * Execute the query and return the filtered Set.
534: * The query is executed with the parameters set by the Map values. Each
535: * Map entry consists of a key which is the name of the parameter in the
536: * declareParameters method, and a value which is the value used in
537: * the execute method. The keys in the Map and the declared parameters
538: * must exactly match or a JDOUserException is thrown.
539: * @return the filtered Set.
540: * @see #executeWithArray(java.lang.Object[] parameters)
541: * @param amap the Map containing all of the parameters.
542: */
543: public Object executeWithMap(Map amap) {
544: beforeExecute(amap);
545: try {
546: Object res = qc.execute(amap, pm, this );
547: if (!unique) {
548: results.add(res);
549: }
550: return res;
551: } catch (JDOException e) {
552: throw e;
553: } catch (Exception e) {
554: logger.log(BasicLevel.ERROR, "execute failed", e);
555: throw new JDOException("Impossible to execute a query ", e);
556: }
557: }
558:
559: /**
560: * Execute the query and return the filtered Set.
561: * <P>The execution of the query obtains the values of the parameters and
562: * matches them against the declared parameters in order. The names
563: * of the declared parameters are ignored. The type of
564: * the declared parameters must match the type of the passed parameters,
565: * except that the passed parameters might need to be unwrapped to get
566: * their primitive values.
567: *
568: * <P>The filter, import, declared parameters, declared variables, and
569: * ordering statements are verified for consistency.
570: *
571: * <P>Each element in the candidate Set is examined to see that it
572: * is assignment compatible to the Class of the query. It is then evaluated
573: * by the boolean expression of the filter. The element passes the filter
574: * if there exist unique values for all variables for which the filter
575: * expression evaluates to true.
576: * @return the filtered Set.
577: * @param anarray the Object array with all of the parameters.
578: */
579: public Object executeWithArray(Object[] anarray) {
580: beforeExecute(anarray);
581: try {
582: Object res = qc.execute(anarray, pm, this );
583: if (!unique) {
584: results.add(res);
585: }
586: return res;
587: } catch (JDOException e) {
588: throw e;
589: } catch (Exception e) {
590: logger.log(BasicLevel.ERROR, "execute failed", e);
591: throw new JDOException("Impossible to execute a query ", e);
592: }
593: }
594:
595: /**
596: * Get the PersistenceManager associated with this Query.
597: * <P>If this Query was restored from a serialized form, it has no
598: * PersistenceManager, and this method returns null.
599: * @return the PersistenceManager associated with this Query.
600: */
601: public PersistenceManager getPersistenceManager() {
602: return pm;
603: }
604:
605: /**
606: * Close a query result and release any resources
607: * associated with it. The parameter is the return from execute(...) and
608: * might have iterators open on it. Iterators associated with the query
609: * result are invalidated: they return false to hasNext() and throw
610: * NoSuchElementException to next().
611: *
612: * This method makes nothing, all is done by the SpeedoCompiledQuery
613: * object. This object is never closed, and could be reused in the
614: * future.
615: *
616: * @param queryResult the result of execute(...) on this Query instance.
617: */
618: public void close(Object queryResult) {
619: if (queryResult instanceof JDOQueryResultList) {
620: ((JDOQueryResultList) queryResult).close();
621: int i = 0;
622: while (i < results.size() && results.get(i) != queryResult) {
623: i++;
624: }
625: if (i < results.size()) {
626: results.remove(i);
627: }
628: }
629: }
630:
631: /**
632: * Close all query results associated with this Query
633: * instance, and release all resources associated with them. The query
634: * results might have iterators open on them. Iterators associated with the
635: * query results are invalidated: they return false to hasNext() and throw
636: * NoSuchElementException to next().
637: */
638: public void closeAll() {
639: for (int i = 0; i < results.size(); i++) {
640: Object queryResult = results.get(i);
641: if (queryResult instanceof JDOQueryResultList) {
642: ((JDOQueryResultList) queryResult).close();
643: }
644: }
645: results.clear();
646: }
647:
648: public FetchPlan getFetchPlan() {
649: return fetchPlan;
650: }
651:
652: public void setFetchPlan(FetchPlan fp) {
653: assertModifiable();
654: fetchPlan = fp;
655: }
656:
657: public long deletePersistentAll() {
658: return deletePersistentAll(new Object[0]);
659: }
660:
661: public long deletePersistentAll(Map params) {
662: beforeDelete(params);
663: try {
664: Long res = (Long) qc.execute(params, pm, this );
665: if (!unique) {
666: results.add(res);
667: }
668: return res.longValue();
669: } catch (JDOException e) {
670: throw e;
671: } catch (Exception e) {
672: logger.log(BasicLevel.ERROR, "execute failed", e);
673: throw new JDOException("Impossible to execute a query ", e);
674: }
675: }
676:
677: public long deletePersistentAll(Object[] params) {
678: beforeDelete(params);
679: try {
680: Long res = (Long) qc.execute(params, pm, this );
681: if (!unique) {
682: results.add(res);
683: }
684: return res.longValue();
685: } catch (JDOException e) {
686: throw e;
687: } catch (Exception e) {
688: logger.log(BasicLevel.ERROR, "execute failed", e);
689: throw new JDOException("Impossible to execute a query ", e);
690: }
691: }
692:
693: public void setGrouping(String arg0) {
694: assertModifiable();
695: hasChanged = true;
696: this .grouping = arg0;
697: }
698:
699: public void setRange(long first, long last) {
700: assertModifiable();
701: indexFirst = first;
702: indexLast = last;
703: }
704:
705: public void setUnique(boolean _unique) {
706: assertModifiable();
707: this .unique = _unique;
708: }
709:
710: public void setResult(String _result) {
711: assertModifiable();
712: hasChanged = true;
713: this .result = _result;
714: }
715:
716: public void setResultClass(Class _resultClass) {
717: assertModifiable();
718: this .resultClass = _resultClass;
719: }
720:
721: public Map extensions = null;
722:
723: public void setExtensions(Map exts) {
724: assertModifiable();
725: this .extensions = exts;
726: }
727:
728: public void addExtension(String key, Object value) {
729: assertModifiable();
730: if (extensions == null) {
731: if (value == null) {
732: return;
733: }
734: extensions = new HashMap();
735: }
736: if (value == null) {
737: extensions.remove(key);
738: } else {
739: extensions.put(key, value);
740: }
741: }
742:
743: boolean modifiable = true;
744:
745: public boolean isUnmodifiable() {
746: return modifiable;
747: }
748:
749: public void setUnmodifiable() {
750: modifiable = false;
751: }
752:
753: public void setRange(String arg0) {
754: // TODO implement JDO Query setRange(String)
755: }
756:
757: // PRIVATE METHODS //
758: //-----------------//
759:
760: private void beforeExecute(Object parameterValues) {
761: int size = 0;
762: if (parameterValues != null) {
763: if (parameterValues instanceof Map) {
764: size = ((Map) parameterValues).size();
765: } else if (parameterValues.getClass().isArray()) {
766: size = ((Object[]) parameterValues).length;
767: }
768: }
769: if (parameters != null && size == 0 && parameters.length() > 0)
770: throw new JDOUserException(
771: "Parameters in not null, and you try to execute without parameters");
772: if (pm.isPOMClosed())
773: throw new JDOFatalUserException(
774: "Impossible to use the query: the persistent manager is closed.");
775: if (parameterValues != null && parameters != null) {
776: if (parameterValues instanceof Map) {
777: treatSpeedoHints((Map) parameterValues);
778: } else if (parameterValues.getClass().isArray()) {
779: treatSpeedoHints((Object[]) parameterValues);
780: }
781: }
782: if (hasChanged) {
783: compile();
784: }
785: }
786:
787: private void beforeDelete(Object parameterValues) {
788: //Load all identifier in order to take locks
789: boolean concurrencyManagedBySpeedo = false;
790: //TODO: compute concurrencyManagedBySpeedo
791: if (concurrencyManagedBySpeedo) {
792: boolean mustLoad = DeleteCallback.class
793: .isAssignableFrom(candidateClass);
794: //TODO: take in account listener in addition to DeleteCallback
795: //home.
796: type = TYPE_SELECT;
797: hasChanged = true;
798: withPrefetch = mustLoad;
799: this .fetchIdentifierOnly = !mustLoad;
800: compile();
801: try {
802: Collection toRemoved;
803: if (parameterValues instanceof Map) {
804: toRemoved = (Collection) qc.execute(
805: (Map) parameterValues, pm, this );
806: } else if (parameterValues.getClass().isArray()) {
807: toRemoved = (Collection) qc.execute(
808: (Object[]) parameterValues, pm, this );
809: } else {
810: throw new SpeedoRuntimeException(
811: "Bad state: no param specified in query");
812: }
813: for (Iterator it = toRemoved.iterator(); it.hasNext();) {
814: Object o = it.next();
815: if (o instanceof PersistentObjectItf) {
816: pm.speedoDeletePersistent(o);
817: StateItf s = ((PersistentObjectItf) o)
818: .speedoGetState();
819: s.setFlushed(true);
820: } else {
821: pm.speedoDeletePersistent(o, candidateClass);
822: }
823: }
824: pm.deletePersistentAll(toRemoved);
825: closeAll();
826: } catch (Exception e) {
827: throw new JDOException("", ExceptionHelper.getNested(e));
828: }
829: }
830: type = TYPE_DELETE;
831: hasChanged = true;
832: withPrefetch = false;
833: beforeExecute(parameterValues);
834: }
835:
836: private void beforeDelete(Map parameterValues) {
837:
838: if (type != TYPE_DELETE) {
839: hasChanged = true;
840: withPrefetch = false;
841: type = TYPE_DELETE;
842: }
843: beforeExecute(parameterValues);
844: }
845:
846: private void assertPMIsOpen() {
847: if (pm.isPOMClosed())
848: throw new JDOUserException(
849: "The persistence manager is closed.");
850: }
851:
852: private void assertModifiable() {
853: if (!modifiable)
854: throw new JDOUserException(
855: "The query has been marked as not modifiable.");
856: }
857:
858: private void assertParameters() {
859: if (parameters == null)
860: throw new JDOUserException(
861: "Parameters string can not be null");
862: }
863:
864: private void assertVariables() {
865: if (variables == null)
866: throw new JDOUserException(
867: "variables string can not be null");
868: }
869:
870: private void assertCandidateClass() {
871: if (candidateClass == null)
872: throw new JDOUserException(
873: "candidate class can not be null");
874: }
875:
876: private void assertExtentClass() {
877: if (extentClass == null)
878: throw new JDOUserException("Extent class can not be null");
879: }
880:
881: private void assertCandidateInstances() {
882: if (candidateInstances == null)
883: throw new JDOUserException(
884: "candidate Collection can not be null");
885: }
886: }
|