KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > query > ProcedureQuery


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56
57 package org.objectstyle.cayenne.query;
58
59 import java.util.ArrayList JavaDoc;
60 import java.util.Collection JavaDoc;
61 import java.util.Collections JavaDoc;
62 import java.util.HashMap JavaDoc;
63 import java.util.List JavaDoc;
64 import java.util.Map JavaDoc;
65
66 import org.objectstyle.cayenne.CayenneRuntimeException;
67 import org.objectstyle.cayenne.access.jdbc.ColumnDescriptor;
68 import org.objectstyle.cayenne.access.jdbc.RowDescriptor;
69 import org.objectstyle.cayenne.map.Procedure;
70 import org.objectstyle.cayenne.map.QueryBuilder;
71 import org.objectstyle.cayenne.util.XMLEncoder;
72 import org.objectstyle.cayenne.util.XMLSerializable;
73
74 /**
75  * A query based on Procedure. Can be used as a select query, or as a query of an
76  * arbitrary complexity, performing data modification, selecting data (possibly with
77  * multiple result sets per call), returning values via OUT parameters.
78  * <h3>Execution with DataContext</h3>
79  * <h4>Reading OUT parameters</h4>
80  * <p>
81  * If a ProcedureQuery has OUT parameters, they are wrapped in a separate List in the
82  * query result. Such list will contain a single Map with OUT parameter values.
83  * </p>
84  * <h4>Using ProcedureQuery as a GenericSelectQuery</h4>
85  * <p>
86  * Executing ProcedureQuery via
87  * {@link org.objectstyle.cayenne.access.DataContext#performQuery(GenericSelectQuery)}
88  * makes sense only if the stored procedure returns a single result set (or alternatively
89  * returns a result via OUT parameters and no other result sets). It is still OK if data
90  * modification occurs as a side effect. However if the query returns more then one result
91  * set, a more generic form should be used:
92  * {@link org.objectstyle.cayenne.access.DataContext#performQueries(java.util.Collection,
93  * org.objectstyle.cayenne.access.OperationObserver) DataContextperformQueries(Collection,
94  * OperationObserver)}. Use {@link org.objectstyle.cayenne.access.QueryResult}as a
95  * convenient generic OperationObserver implementation.
96  * </p>
97  *
98  * @author Andrei Adamchik
99  */

100 public class ProcedureQuery extends AbstractQuery implements GenericSelectQuery,
101         ParameterizedQuery, XMLSerializable {
102
103     /**
104      * If set, allows to fetch results as DataObjects.
105      *
106      * @since 1.1
107      */

108     protected String JavaDoc resultClassName;
109
110     protected Map JavaDoc parameters = new HashMap JavaDoc();
111     protected SelectExecutionProperties selectProperties = new SelectExecutionProperties();
112     protected boolean selecting;
113
114     // TODO: ColumnDescriptor is not XMLSerializable so we can't store
115
// it in a DataMap
116
/**
117      * @since 1.2
118      */

119     protected List JavaDoc resultDescriptors;
120
121     /**
122      * Creates an empty procedure query.
123      */

124     public ProcedureQuery() {
125         // for backwards compatibility we go against usual default...
126
selectProperties.setFetchingDataRows(true);
127     }
128
129     /**
130      * Creates a ProcedureQuery based on a Procedure object.
131      */

132     public ProcedureQuery(Procedure procedure) {
133         // for backwards compatibility we go against usual default...
134
selectProperties.setFetchingDataRows(true);
135         setRoot(procedure);
136     }
137
138     /**
139      * Creates a ProcedureQuery based on a stored procedure.
140      * <p>
141      * Performance Note: with current EntityResolver implementation it is preferrable to
142      * use Procedure object instead of String as a query root. String root can cause
143      * unneeded EntityResolver reindexing on every call. See this mailing list thread: <a
144      * HREF="http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html">
145      * http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html</a>
146      * </p>
147      *
148      * @param procedureName A name of the stored procedure. For this query to work, a
149      * procedure with this name must be mapped in Cayenne.
150      */

151     public ProcedureQuery(String JavaDoc procedureName) {
152         // for backwards compatibility we go against usual default...
153
selectProperties.setFetchingDataRows(true);
154
155         setRoot(procedureName);
156     }
157
158     /**
159      * @since 1.1
160      */

161     public ProcedureQuery(Procedure procedure, Class JavaDoc resultType) {
162         setRoot(procedure);
163         setResultClassName(resultType != null ? resultType.getName() : null);
164     }
165
166     /**
167      * <p>
168      * Performance Note: with current EntityResolver implementation it is preferrable to
169      * use Procedure object instead of String as a query root. String root can cause
170      * unneeded EntityResolver reindexing on every call. See this mailing list thread: <a
171      * HREF="http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html">
172      * http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html</a>
173      * </p>
174      *
175      * @since 1.1
176      */

177     public ProcedureQuery(String JavaDoc procedureName, Class JavaDoc resultType) {
178         setRoot(procedureName);
179         setResultClassName(resultType != null ? resultType.getName() : null);
180     }
181
182     /**
183      * Returns a List of #{@link RowDescriptor} objects describing query ResultSets in
184      * the order they are returned by the stored procedure.
185      * <p>
186      * <i>Note that if a procedure returns ResultSet in an OUT parameter, it is returned
187      * prior to any other result sets (though in practice database engines usually support
188      * only one mechanism for returning result sets. </i>
189      * </p>
190      *
191      * @since 1.2
192      */

193     public List JavaDoc getResultDescriptors() {
194         return resultDescriptors != null ? resultDescriptors : Collections.EMPTY_LIST;
195     }
196
197     /**
198      * Adds a descriptor for a single ResultSet. More than one descriptor can be added by
199      * calling this method multiple times in the order of described ResultSet appearance
200      * in the procedure results.
201      *
202      * @since 1.2
203      */

204     public synchronized void addResultDescriptor(ColumnDescriptor[] descriptor) {
205         if (resultDescriptors == null) {
206             resultDescriptors = new ArrayList JavaDoc(2);
207         }
208
209         resultDescriptors.add(descriptor);
210     }
211
212     /**
213      * Removes result descriptor from the list of descriptors.
214      *
215      * @since 1.2
216      */

217     public void removeResultDescriptor(ColumnDescriptor[] descriptor) {
218         if (resultDescriptors != null) {
219             resultDescriptors.remove(descriptor);
220         }
221     }
222
223     /**
224      * Calls "makeProcedure" on the visitor.
225      *
226      * @since 1.2
227      */

228     public SQLAction createSQLAction(SQLActionVisitor visitor) {
229         return visitor.procedureAction(this);
230     }
231
232     /**
233      * Initializes query parameters using a set of properties.
234      *
235      * @since 1.1
236      */

237     public void initWithProperties(Map JavaDoc properties) {
238
239         // must init defaults even if properties are empty
240
if (properties == null) {
241             properties = Collections.EMPTY_MAP;
242         }
243
244         selectProperties.initWithProperties(properties);
245     }
246
247     /**
248      * Prints itself as XML to the provided PrintWriter.
249      *
250      * @since 1.1
251      */

252     public void encodeAsXML(XMLEncoder encoder) {
253         encoder.print("<query name=\"");
254         encoder.print(getName());
255         encoder.print("\" factory=\"");
256         encoder.print("org.objectstyle.cayenne.map.ProcedureQueryBuilder");
257
258         encoder.print("\" root=\"");
259         encoder.print(QueryBuilder.PROCEDURE_ROOT);
260
261         String JavaDoc rootString = null;
262
263         if (root instanceof String JavaDoc) {
264             rootString = root.toString();
265         }
266         else if (root instanceof Procedure) {
267             rootString = ((Procedure) root).getName();
268         }
269
270         if (rootString != null) {
271             encoder.print("\" root-name=\"");
272             encoder.print(rootString);
273         }
274
275         if (resultClassName != null) {
276             encoder.print("\" result-type=\"");
277             encoder.print(resultClassName);
278         }
279
280         if (!selecting) {
281             encoder.print("\" selecting=\"false");
282         }
283
284         encoder.println("\">");
285
286         encoder.indent(1);
287
288         selectProperties.encodeAsXML(encoder);
289
290         encoder.indent(-1);
291         encoder.println("</query>");
292     }
293
294     /**
295      * Creates and returns a new ProcedureQuery built using this query as a prototype and
296      * substituting template parameters with the values from the map.
297      *
298      * @since 1.1
299      */

300     public Query createQuery(Map JavaDoc parameters) {
301         // create a query replica
302
ProcedureQuery query = new ProcedureQuery();
303
304         if (root != null) {
305             query.setRoot(root);
306         }
307
308         query.setLoggingLevel(logLevel);
309         query.setResultClassName(resultClassName);
310
311         selectProperties.copyToProperties(query.selectProperties);
312         query.setParameters(parameters);
313
314         // TODO: implement algorithm for building the name based on the original name and
315
// the hashcode of the map of parameters. This way query clone can take advantage
316
// of caching.
317
return query;
318     }
319
320     public String JavaDoc getCachePolicy() {
321         return selectProperties.getCachePolicy();
322     }
323
324     public void setCachePolicy(String JavaDoc policy) {
325         this.selectProperties.setCachePolicy(policy);
326     }
327
328     public int getFetchLimit() {
329         return selectProperties.getFetchLimit();
330     }
331
332     public void setFetchLimit(int fetchLimit) {
333         this.selectProperties.setFetchLimit(fetchLimit);
334     }
335
336     public int getPageSize() {
337         return selectProperties.getPageSize();
338     }
339
340     public void setPageSize(int pageSize) {
341         selectProperties.setPageSize(pageSize);
342     }
343
344     public void setFetchingDataRows(boolean flag) {
345         selectProperties.setFetchingDataRows(flag);
346     }
347
348     public boolean isFetchingDataRows() {
349         return selectProperties.isFetchingDataRows();
350     }
351
352     public boolean isRefreshingObjects() {
353         return selectProperties.isRefreshingObjects();
354     }
355
356     public void setRefreshingObjects(boolean flag) {
357         selectProperties.setRefreshingObjects(flag);
358     }
359
360     public boolean isResolvingInherited() {
361         return selectProperties.isResolvingInherited();
362     }
363
364     public void setResolvingInherited(boolean b) {
365         selectProperties.setResolvingInherited(b);
366     }
367
368     /**
369      * Adds a named parameter to the internal map of parameters.
370      *
371      * @since 1.1
372      */

373     public synchronized void addParameter(String JavaDoc name, Object JavaDoc value) {
374         parameters.put(name, value);
375     }
376
377     /**
378      * @since 1.1
379      */

380     public synchronized void removeParameter(String JavaDoc name) {
381         parameters.remove(name);
382     }
383
384     /**
385      * Returns a map of procedure parameters.
386      *
387      * @since 1.1
388      */

389     public Map JavaDoc getParameters() {
390         return parameters;
391     }
392
393     /**
394      * Sets a map of parameters.
395      *
396      * @since 1.1
397      */

398     public synchronized void setParameters(Map JavaDoc parameters) {
399         this.parameters.clear();
400
401         if (parameters != null) {
402             this.parameters.putAll(parameters);
403         }
404     }
405
406     /**
407      * Cleans up all configured parameters.
408      *
409      * @since 1.1
410      */

411     public synchronized void clearParameters() {
412         this.parameters.clear();
413     }
414
415     /**
416      * Returns an optional result type of the query.
417      *
418      * @since 1.1
419      */

420     public String JavaDoc getResultClassName() {
421         return resultClassName;
422     }
423
424     /**
425      * Returns Java class of the DataObjects returned by this query. If ClassLoader
426      * argument is null, uses Class.forName(..) to discover result class.
427      *
428      * @since 1.1
429      */

430     public Class JavaDoc getResultClass(ClassLoader JavaDoc classLoader) {
431         if (this.getResultClassName() == null) {
432             return null;
433         }
434
435         try {
436             // tolerate null class loader
437
if (classLoader == null) {
438                 return Class.forName(this.getResultClassName());
439             }
440             else {
441                 return classLoader.loadClass(this.getResultClassName());
442             }
443         }
444         catch (ClassNotFoundException JavaDoc e) {
445             throw new CayenneRuntimeException("Failed to load class for name '"
446                     + this.getResultClassName()
447                     + "': "
448                     + e.getMessage(), e);
449         }
450     }
451
452     /**
453      * Sets optional result type of the query. A Class of the result type must be a
454      * DataObject implementation mapped in Cayenne.
455      *
456      * @since 1.1
457      */

458     public void setResultClassName(String JavaDoc resultClassName) {
459         this.resultClassName = resultClassName;
460     }
461
462     /**
463      * Returns true if ProcedureQuery is expected to return a ResultSet.
464      *
465      * @since 1.1
466      */

467     public boolean isSelecting() {
468         return selecting;
469     }
470
471     /**
472      * Sets whether ProcedureQuery is expected to return a ResultSet.
473      *
474      * @since 1.1
475      */

476     public void setSelecting(boolean b) {
477         selecting = b;
478     }
479
480     /**
481      * Returns a collection of joint prefetches.
482      *
483      * @since 1.2
484      */

485     public Collection JavaDoc getJointPrefetches() {
486         return selectProperties.getJointPrefetches();
487     }
488
489     /**
490      * Adds a joint prefetch.
491      *
492      * @since 1.2
493      */

494     public void addJointPrefetch(String JavaDoc relationshipPath) {
495         selectProperties.addJointPrefetch(relationshipPath);
496     }
497
498     /**
499      * Adds all joint prefetches from a provided collection.
500      *
501      * @since 1.2
502      */

503     public void addJointPrefetches(Collection JavaDoc relationshipPaths) {
504         selectProperties.addJointPrefetches(relationshipPaths);
505     }
506
507     /**
508      * Clears all joint prefetches.
509      *
510      * @since 1.2
511      */

512     public void clearJointPrefetches() {
513         selectProperties.clearJointPrefetches();
514     }
515
516     /**
517      * Removes joint prefetch.
518      *
519      * @since 1.2
520      */

521     public void removeJointPrefetch(String JavaDoc relationshipPath) {
522         selectProperties.removeJointPrefetch(relationshipPath);
523     }
524 }
Popular Tags