KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.query;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28
29 import org.apache.cayenne.access.jdbc.ColumnDescriptor;
30 import org.apache.cayenne.access.jdbc.RowDescriptor;
31 import org.apache.cayenne.map.EntityResolver;
32 import org.apache.cayenne.map.Procedure;
33 import org.apache.cayenne.map.QueryBuilder;
34 import org.apache.cayenne.util.XMLEncoder;
35 import org.apache.cayenne.util.XMLSerializable;
36
37 /**
38  * A query based on Procedure. Can be used as a select query, or as a query of an
39  * arbitrary complexity, performing data modification, selecting data (possibly with
40  * multiple result sets per call), returning values via OUT parameters.
41  * <h3>Execution with DataContext</h3>
42  * <h4>Reading OUT parameters</h4>
43  * <p>
44  * If a ProcedureQuery has OUT parameters, they are wrapped in a separate List in the
45  * query result. Such list will contain a single Map with OUT parameter values.
46  * </p>
47  * <h4>Using ProcedureQuery as a GenericSelectQuery</h4>
48  * <p>
49  * Executing ProcedureQuery via
50  * {@link org.apache.cayenne.access.DataContext#performQuery(Query)} makes sense only if
51  * the stored procedure returns a single result set (or alternatively returns a result via
52  * OUT parameters and no other result sets). It is still OK if data modification occurs as
53  * a side effect. However if the query returns more then one result set, a more generic
54  * form should be used:
55  * {@link org.apache.cayenne.access.DataContext#performGenericQuery(Query)}.
56  * </p>
57  *
58  * @author Andrus Adamchik
59  */

60 public class ProcedureQuery extends AbstractQuery implements ParameterizedQuery,
61         XMLSerializable {
62
63     /**
64      * @since 1.2
65      */

66     protected String JavaDoc resultEntityName;
67
68     /**
69      * @since 1.2
70      */

71     protected Class JavaDoc resultClass;
72
73     protected Map JavaDoc parameters = new HashMap JavaDoc();
74
75     ProcedureQueryMetadata metaData = new ProcedureQueryMetadata();
76
77     // TODO: ColumnDescriptor is not XMLSerializable so we can't store
78
// it in a DataMap
79
/**
80      * @since 1.2
81      */

82     protected List JavaDoc resultDescriptors;
83
84     /**
85      * Creates an empty procedure query.
86      */

87     public ProcedureQuery() {
88         // for backwards compatibility we go against usual default...
89
metaData.setFetchingDataRows(true);
90     }
91
92     /**
93      * Creates a ProcedureQuery based on a Procedure object.
94      */

95     public ProcedureQuery(Procedure procedure) {
96         // for backwards compatibility we go against usual default...
97
metaData.setFetchingDataRows(true);
98         setRoot(procedure);
99     }
100
101     /**
102      * Creates a ProcedureQuery based on a stored procedure.
103      * <p>
104      * Performance Note: with current EntityResolver implementation it is preferrable to
105      * use Procedure object instead of String as a query root. String root can cause
106      * unneeded EntityResolver reindexing on every call. See this mailing list thread: <a
107      * HREF="http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html">
108      * http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html</a>
109      * </p>
110      *
111      * @param procedureName A name of the stored procedure. For this query to work, a
112      * procedure with this name must be mapped in Cayenne.
113      */

114     public ProcedureQuery(String JavaDoc procedureName) {
115         // for backwards compatibility we go against usual default...
116
metaData.setFetchingDataRows(true);
117
118         setRoot(procedureName);
119     }
120
121     /**
122      * @since 1.1
123      */

124     public ProcedureQuery(Procedure procedure, Class JavaDoc resultType) {
125         setRoot(procedure);
126
127         this.resultClass = resultType;
128     }
129
130     /**
131      * <p>
132      * Performance Note: with current EntityResolver implementation it is preferrable to
133      * use Procedure object instead of String as a query root. String root can cause
134      * unneeded EntityResolver reindexing on every call. See this mailing list thread: <a
135      * HREF="http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html">
136      * http://objectstyle.org/cayenne/lists/cayenne-user/2005/01/0109.html</a>
137      * </p>
138      *
139      * @since 1.1
140      */

141     public ProcedureQuery(String JavaDoc procedureName, Class JavaDoc resultType) {
142         setRoot(procedureName);
143
144         this.resultClass = resultType;
145     }
146
147     /**
148      * @since 1.2
149      */

150     public QueryMetadata getMetaData(EntityResolver resolver) {
151
152         metaData.resolve(root, resultClass != null
153                 ? (Object JavaDoc) resultClass
154                 : resultEntityName, resolver, this);
155         return metaData;
156     }
157
158     /**
159      * Returns a List of #{@link RowDescriptor} objects describing query ResultSets in
160      * the order they are returned by the stored procedure.
161      * <p>
162      * <i>Note that if a procedure returns ResultSet in an OUT parameter, it is returned
163      * prior to any other result sets (though in practice database engines usually support
164      * only one mechanism for returning result sets. </i>
165      * </p>
166      *
167      * @since 1.2
168      */

169     public List JavaDoc getResultDescriptors() {
170         return resultDescriptors != null ? resultDescriptors : Collections.EMPTY_LIST;
171     }
172
173     /**
174      * Adds a descriptor for a single ResultSet. More than one descriptor can be added by
175      * calling this method multiple times in the order of described ResultSet appearance
176      * in the procedure results.
177      *
178      * @since 1.2
179      */

180     public synchronized void addResultDescriptor(ColumnDescriptor[] descriptor) {
181         if (resultDescriptors == null) {
182             resultDescriptors = new ArrayList JavaDoc(2);
183         }
184
185         resultDescriptors.add(descriptor);
186     }
187
188     /**
189      * Removes result descriptor from the list of descriptors.
190      *
191      * @since 1.2
192      */

193     public void removeResultDescriptor(ColumnDescriptor[] descriptor) {
194         if (resultDescriptors != null) {
195             resultDescriptors.remove(descriptor);
196         }
197     }
198
199     /**
200      * Calls "makeProcedure" on the visitor.
201      *
202      * @since 1.2
203      */

204     public SQLAction createSQLAction(SQLActionVisitor visitor) {
205         return visitor.procedureAction(this);
206     }
207
208     /**
209      * Initializes query parameters using a set of properties.
210      *
211      * @since 1.1
212      */

213     public void initWithProperties(Map JavaDoc properties) {
214
215         // must init defaults even if properties are empty
216
if (properties == null) {
217             properties = Collections.EMPTY_MAP;
218         }
219
220         metaData.initWithProperties(properties);
221     }
222
223     /**
224      * Prints itself as XML to the provided PrintWriter.
225      *
226      * @since 1.1
227      */

228     public void encodeAsXML(XMLEncoder encoder) {
229         encoder.print("<query name=\"");
230         encoder.print(getName());
231         encoder.print("\" factory=\"");
232         encoder.print("org.apache.cayenne.map.ProcedureQueryBuilder");
233
234         encoder.print("\" root=\"");
235         encoder.print(QueryBuilder.PROCEDURE_ROOT);
236
237         String JavaDoc rootString = null;
238
239         if (root instanceof String JavaDoc) {
240             rootString = root.toString();
241         }
242         else if (root instanceof Procedure) {
243             rootString = ((Procedure) root).getName();
244         }
245
246         if (rootString != null) {
247             encoder.print("\" root-name=\"");
248             encoder.print(rootString);
249         }
250
251         if (resultEntityName != null) {
252             encoder.print("\" result-entity=\"");
253             encoder.print(resultEntityName);
254         }
255
256         encoder.println("\">");
257         encoder.indent(1);
258
259         metaData.encodeAsXML(encoder);
260
261         encoder.indent(-1);
262         encoder.println("</query>");
263     }
264
265     /**
266      * Creates and returns a new ProcedureQuery built using this query as a prototype and
267      * substituting template parameters with the values from the map.
268      *
269      * @since 1.1
270      */

271     public Query createQuery(Map JavaDoc parameters) {
272         // create a query replica
273
ProcedureQuery query = new ProcedureQuery();
274
275         if (root != null) {
276             query.setRoot(root);
277         }
278
279         query.setResultEntityName(resultEntityName);
280         query.metaData.copyFromInfo(this.metaData);
281         query.setParameters(parameters);
282
283         // TODO: implement algorithm for building the name based on the original name and
284
// the hashcode of the map of parameters. This way query clone can take advantage
285
// of caching.
286
return query;
287     }
288
289     public String JavaDoc getCachePolicy() {
290         return metaData.getCachePolicy();
291     }
292
293     public void setCachePolicy(String JavaDoc policy) {
294         this.metaData.setCachePolicy(policy);
295     }
296     
297     /**
298      * @since 3.0
299      */

300     public String JavaDoc[] getCacheGroups() {
301         return metaData.getCacheGroups();
302     }
303
304     /**
305      * @since 3.0
306      */

307     public void setCacheGroups(String JavaDoc[] cachGroups) {
308         this.metaData.setCacheGroups(cachGroups);
309     }
310
311     public int getFetchLimit() {
312         return metaData.getFetchLimit();
313     }
314
315     public void setFetchLimit(int fetchLimit) {
316         this.metaData.setFetchLimit(fetchLimit);
317     }
318
319     public int getPageSize() {
320         return metaData.getPageSize();
321     }
322
323     public void setPageSize(int pageSize) {
324         metaData.setPageSize(pageSize);
325     }
326
327     public void setFetchingDataRows(boolean flag) {
328         metaData.setFetchingDataRows(flag);
329     }
330
331     public boolean isFetchingDataRows() {
332         return metaData.isFetchingDataRows();
333     }
334
335     public boolean isRefreshingObjects() {
336         return metaData.isRefreshingObjects();
337     }
338
339     public void setRefreshingObjects(boolean flag) {
340         metaData.setRefreshingObjects(flag);
341     }
342
343     public boolean isResolvingInherited() {
344         return metaData.isResolvingInherited();
345     }
346
347     public void setResolvingInherited(boolean b) {
348         metaData.setResolvingInherited(b);
349     }
350
351     /**
352      * Adds a named parameter to the internal map of parameters.
353      *
354      * @since 1.1
355      */

356     public synchronized void addParameter(String JavaDoc name, Object JavaDoc value) {
357         parameters.put(name, value);
358     }
359
360     /**
361      * @since 1.1
362      */

363     public synchronized void removeParameter(String JavaDoc name) {
364         parameters.remove(name);
365     }
366
367     /**
368      * Returns a map of procedure parameters.
369      *
370      * @since 1.1
371      */

372     public Map JavaDoc getParameters() {
373         return parameters;
374     }
375
376     /**
377      * Sets a map of parameters.
378      *
379      * @since 1.1
380      */

381     public synchronized void setParameters(Map JavaDoc parameters) {
382         this.parameters.clear();
383
384         if (parameters != null) {
385             this.parameters.putAll(parameters);
386         }
387     }
388
389     /**
390      * Cleans up all configured parameters.
391      *
392      * @since 1.1
393      */

394     public synchronized void clearParameters() {
395         this.parameters.clear();
396     }
397
398     /**
399      * @since 1.2
400      */

401     public PrefetchTreeNode getPrefetchTree() {
402         return metaData.getPrefetchTree();
403     }
404
405     /**
406      * Adds a prefetch.
407      *
408      * @since 1.2
409      */

410     public PrefetchTreeNode addPrefetch(String JavaDoc prefetchPath) {
411         // by default use JOINT_PREFETCH_SEMANTICS
412
return metaData.addPrefetch(
413                 prefetchPath,
414                 PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
415     }
416
417     /**
418      * @since 1.2
419      */

420     public void removePrefetch(String JavaDoc prefetch) {
421         metaData.removePrefetch(prefetch);
422     }
423
424     /**
425      * Adds all prefetches from a provided collection.
426      *
427      * @since 1.2
428      */

429     public void addPrefetches(Collection JavaDoc prefetches) {
430         metaData.addPrefetches(prefetches, PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
431     }
432
433     /**
434      * Clears all prefetches.
435      *
436      * @since 1.2
437      */

438     public void clearPrefetches() {
439         metaData.clearPrefetches();
440     }
441
442     /**
443      * @since 1.2
444      */

445     public String JavaDoc getResultEntityName() {
446         return resultEntityName;
447     }
448
449     /**
450      * @since 1.2
451      */

452     public void setResultEntityName(String JavaDoc resultEntityName) {
453         this.resultEntityName = resultEntityName;
454     }
455 }
456
Popular Tags