KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > queryframework > ReadAllQuery


1 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
2
package oracle.toplink.essentials.queryframework;
3
4 import java.util.*;
5 import oracle.toplink.essentials.internal.helper.*;
6 import oracle.toplink.essentials.internal.queryframework.*;
7 import oracle.toplink.essentials.exceptions.*;
8 import oracle.toplink.essentials.expressions.*;
9 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
10 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
11 import oracle.toplink.essentials.internal.sessions.AbstractSession;
12
13 /**set
14  * <p><b>Purpose</b>:
15  * Concrete class for all read queries involving a collection of objects.
16  * <p>
17  * <p><b>Responsibilities</b>:
18  * Return a container of the objects generated by the query.
19  * Implements the inheritance feature when dealing with abstract descriptors
20  *
21  * @author Yvon Lavoie
22  * @since TOPLink/Java 1.0
23  */

24 public class ReadAllQuery extends ObjectLevelReadQuery {
25
26     /** Used for ordering support. */
27     protected Vector orderByExpressions;
28
29     /** Used for collection and stream support. */
30     protected ContainerPolicy containerPolicy;
31
32     /**
33      * PUBLIC:
34      * Return a new read all query.
35      * A reference class must be specified before execution.
36      * It is better to provide the class and expression builder on construction to esnure a single expression builder is used.
37      * If no selection criteria is specified this will read all objects of the class from the database.
38      */

39     public ReadAllQuery() {
40         super();
41         this.useCollectionClass(ClassConstants.Vector_class);
42     }
43
44     /**
45      * PUBLIC:
46      * Return a new read all query.
47      * It is better to provide the class and expression builder on construction to esnure a single expression builder is used.
48      * If no selection criteria is specified this will read all objects of the class from the database.
49      */

50     public ReadAllQuery(Class JavaDoc classToRead) {
51         this();
52         setReferenceClass(classToRead);
53     }
54
55     /**
56      * PUBLIC:
57      * Return a new read all query for the class and the selection criteria.
58      */

59     public ReadAllQuery(Class JavaDoc classToRead, Expression selectionCriteria) {
60         this();
61         setReferenceClass(classToRead);
62         setSelectionCriteria(selectionCriteria);
63     }
64
65     /**
66      * PUBLIC:
67      * Return a new read all query for the class.
68      * The expression builder must be used for all associated expressions used with the query.
69      */

70     public ReadAllQuery(Class JavaDoc classToRead, ExpressionBuilder builder) {
71         this();
72         this.defaultBuilder = builder;
73         setReferenceClass(classToRead);
74     }
75
76     /**
77      * PUBLIC:
78      * Return a new read all query.
79      * The call represents a database interaction such as SQL, Stored Procedure.
80      */

81     public ReadAllQuery(Class JavaDoc classToRead, Call call) {
82         this();
83         setReferenceClass(classToRead);
84         setCall(call);
85     }
86
87     /**
88      * PUBLIC:
89      * The expression builder should be provide on creation to ensure only one is used.
90      */

91     public ReadAllQuery(ExpressionBuilder builder) {
92         this();
93         this.defaultBuilder = builder;
94     }
95
96     /**
97      * PUBLIC:
98      * Create a read all query with the database call.
99      */

100     public ReadAllQuery(Call call) {
101         this();
102         setCall(call);
103     }
104
105     /**
106      * PUBLIC:
107      * Order the query results by the object's attribute or query key name.
108      */

109     public void addAscendingOrdering(String JavaDoc queryKeyName) {
110         addOrdering(getExpressionBuilder().get(queryKeyName).ascending());
111     }
112
113     /**
114      * PUBLIC:
115      * Order the query results by the object's attribute or query key name.
116      */

117     public void addDescendingOrdering(String JavaDoc queryKeyName) {
118         addOrdering(getExpressionBuilder().get(queryKeyName).descending());
119     }
120
121     /**
122      * PUBLIC:
123      * Add the ordering expression. This allows for ordering across relationships or functions.
124      * Example: readAllQuery.addOrdering(expBuilder.get("address").get("city").toUpperCase().descending())
125      */

126     public void addOrdering(Expression orderingExpression) {
127         getOrderByExpressions().addElement(orderingExpression);
128         //Bug2804042 Must un-prepare if prepared as the SQL may change.
129
setIsPrepared(false);
130     }
131
132     /**
133      * INTERNAL:
134      * The cache check is done before the prepare as a hit will not require the work to be done.
135      */

136     protected Object JavaDoc checkEarlyReturnImpl(AbstractSession session, AbstractRecord translationRow) {
137         // Check for in-memory only query.
138
if (shouldCheckCacheOnly()) {
139             // assert !isReportQuery();
140
if (shouldUseWrapperPolicy()) {
141                 getContainerPolicy().setElementDescriptor(getDescriptor());
142             }
143
144             // PERF: Fixed to not query each unit of work cache (is not conforming),
145
// avoid hashtable and primary key indexing.
146
// At some point we may need to support some kind of in-memory with conforming option,
147
// but we do not currently allow this.
148
AbstractSession rootSession = session;
149             while (rootSession.isUnitOfWork()) {
150                 rootSession = ((UnitOfWorkImpl)rootSession).getParent();
151             }
152             Vector allCachedVector = rootSession.getIdentityMapAccessor().getAllFromIdentityMap(getSelectionCriteria(), getReferenceClass(), translationRow, getInMemoryQueryIndirectionPolicy(), false);
153
154             // Must ensure that all of the objects returned are correctly registered in the unit of work.
155
if (session.isUnitOfWork()) {
156                 allCachedVector = ((UnitOfWorkImpl)session).registerAllObjects(allCachedVector);
157             }
158
159             return getContainerPolicy().buildContainerFromVector(allCachedVector, session);
160         } else {
161             return null;
162         }
163     }
164
165     /**
166      * INTERNAL:
167      * Check to see if a custom query should be used for this query.
168      * This is done before the query is copied and prepared/executed.
169      * null means there is none.
170      */

171     protected DatabaseQuery checkForCustomQuery(AbstractSession session, AbstractRecord translationRow) {
172         checkDescriptor(session);
173
174         // check if user defined a custom query
175
if ((!isUserDefined()) && isExpressionQuery() && (getSelectionCriteria() == null) && (!hasOrderByExpressions()) && (getDescriptor().getQueryManager().hasReadAllQuery())) {
176             return getDescriptor().getQueryManager().getReadAllQuery();
177         } else {
178             return null;
179         }
180     }
181
182     /**
183      * INTERNAL:
184      * Clone the query.
185      */

186     public Object JavaDoc clone() {
187         ReadAllQuery cloneQuery = (ReadAllQuery)super.clone();
188
189         // Don't use setters as that will trigger unprepare
190
if (hasOrderByExpressions()) {
191             cloneQuery.orderByExpressions = (Vector)getOrderByExpressions().clone();
192         }
193         cloneQuery.containerPolicy = getContainerPolicy().clone(cloneQuery);
194
195         return cloneQuery;
196     }
197
198     /**
199      * INTERNAL:
200      * Conform the result if specified.
201      */

202     protected Object JavaDoc conformResult(Object JavaDoc result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) {
203         ContainerPolicy cp;
204         IdentityHashtable indexedInterimResult = null;
205         Expression selectionCriteriaClone = null;
206
207         if (getSelectionCriteria() != null) {
208             selectionCriteriaClone = (Expression)getSelectionCriteria().clone();
209             selectionCriteriaClone.getBuilder().setSession(unitOfWork);
210             selectionCriteriaClone.getBuilder().setQueryClass(getReferenceClass());
211         }
212         cp = getContainerPolicy();
213
214         // This code is now a great deal different... For one, registration is done
215
// as part of conforming. Also, this should only be called if one actually
216
// is conforming.
217
// First scan the UnitOfWork for conforming instances.
218
// This will walk through the entire cache of registered objects.
219
// Let p be objects from result not in the cache.
220
// Let c be objects from cache.
221
// Presently p intersect c = empty set, but later p subset c.
222
// By checking cache now doesConform will be called p fewer times.
223
indexedInterimResult = unitOfWork.scanForConformingInstances(selectionCriteriaClone, getReferenceClass(), arguments, this);
224
225         // Now conform the result from the database.
226
// Remove any deleted or changed objects that no longer conform.
227
// Deletes will only work for simple queries, queries with or's or anyof's may not return
228
// correct results when untriggered indirection is in the model.
229
Vector fromDatabase = null;
230
231         // When building directly from rows, one of the performance benefits
232
// is that we no longer have to wrap and then unwrap the originals.
233
// result is just a vector, not a container of wrapped originals.
234
if (buildDirectlyFromRows) {
235             Vector rows = (Vector)result;
236             Set identitySet = null;
237             fromDatabase = new Vector(rows.size());
238             for (int i = 0; i < rows.size(); i++) {
239                 Object JavaDoc object = rows.elementAt(i);
240
241                 // null is placed in the row collection for 1-m joining to filter duplicate rows.
242
if (object != null) {
243                     Object JavaDoc clone = conformIndividualResult(object, unitOfWork, arguments, selectionCriteriaClone, indexedInterimResult, buildDirectlyFromRows);
244                     if (clone != null) {
245                         // Avoid duplicates if -m joining was used and a cache hit occured.
246
if (getJoinedAttributeManager().isToManyJoin()) {
247                             if (identitySet == null) {
248                                 identitySet = new TopLinkIdentityHashSet(rows.size());
249                             }
250                             if (!identitySet.contains(clone)) {
251                                 identitySet.add(clone);
252                                 fromDatabase.addElement(clone);
253                             }
254                         } else {
255                             fromDatabase.addElement(clone);
256                         }
257                     }
258                 }
259             }
260         } else {
261             fromDatabase = new Vector(cp.sizeFor(result));
262             AbstractSession sessionToUse = unitOfWork.getParent();
263             for (Object JavaDoc iter = cp.iteratorFor(result); cp.hasNext(iter);) {
264                 Object JavaDoc object = cp.next(iter, sessionToUse);
265                 Object JavaDoc clone = conformIndividualResult(object, unitOfWork, arguments, selectionCriteriaClone, indexedInterimResult, buildDirectlyFromRows);
266                 if (clone != null) {
267                     fromDatabase.addElement(clone);
268                 }
269             }
270         }
271
272         // Now add the unwrapped conforming instances into an appropriate container.
273
// Wrapping is done automatically.
274
// Make sure a vector of exactly the right size is returned.
275
//
276
Object JavaDoc conformedResult = cp.containerInstance(indexedInterimResult.size() + fromDatabase.size());
277         Object JavaDoc eachClone;
278         for (Enumeration enumtr = indexedInterimResult.elements(); enumtr.hasMoreElements();) {
279             eachClone = enumtr.nextElement();
280             cp.addInto(eachClone, conformedResult, unitOfWork);
281         }
282         for (Enumeration enumtr = fromDatabase.elements(); enumtr.hasMoreElements();) {
283             eachClone = enumtr.nextElement();
284             cp.addInto(eachClone, conformedResult, unitOfWork);
285         }
286         return conformedResult;
287     }
288
289     /**
290      * INTERNAL:
291      * Execute the query.
292      * Get the rows and build the object from the rows.
293      * @exception DatabaseException - an error has occurred on the database
294      * @return java.lang.Object collection of objects resulting from execution of query.
295      */

296     protected Object JavaDoc executeObjectLevelReadQuery() throws DatabaseException {
297         Object JavaDoc result = null;
298         if (getContainerPolicy().overridesRead()) {
299             return getContainerPolicy().execute();
300         }
301
302         Vector rows = getQueryMechanism().selectAllRows();
303         setExecutionTime(System.currentTimeMillis());
304         // If using -m joins, must set all rows.
305
if (getJoinedAttributeManager().isToManyJoin()) {
306             getJoinedAttributeManager().setDataResults(rows, getSession());
307         }
308
309         if (getSession().isUnitOfWork()) {
310             result = registerResultInUnitOfWork(rows, (UnitOfWorkImpl)getSession(), getTranslationRow(), true);//
311
} else {
312             result = getQueryMechanism().buildObjectsFromRows(rows);
313         }
314
315         if (shouldIncludeData()) {
316             ComplexQueryResult complexResult = new ComplexQueryResult();
317             complexResult.setResult(result);
318             complexResult.setData(rows);
319             return complexResult;
320         }
321
322         return result;
323     }
324
325     /**
326      * INTERNAL:
327      * Return the query's container policy.
328      * @return oracle.toplink.essentials.internal.queryframework.ContainerPolicy
329      */

330     public ContainerPolicy getContainerPolicy() {
331         return containerPolicy;
332     }
333
334     /**
335      * INTERNAL:
336      * Return the order expressions for the query.
337      */

338     public Vector getOrderByExpressions() {
339         if (orderByExpressions == null) {
340             orderByExpressions = new Vector();
341         }
342         return orderByExpressions;
343     }
344
345     /**
346      * INTERNAL:
347      * The order bys are lazy initialized to conserv space.
348      */

349     public boolean hasOrderByExpressions() {
350         return orderByExpressions != null;
351     }
352
353     /**
354      * INTERNAL:
355      * Verify that we have hierarchical query expressions
356      */

357     public boolean hasHierarchicalExpressions() {
358         return false;
359     }
360
361     /**
362      * INTERNAL:
363      * Return true is this query has batching
364      */

365     public boolean hasBatchReadAttributes() {
366         return false;
367     }
368
369     /**
370      * INTERNAL:
371      * Return if the attribute is specified for batch reading.
372      */

373     public boolean isAttributeBatchRead(String JavaDoc attributeName) {
374         return false;
375     }
376
377     /**
378      * PUBLIC:
379      * Return if this is a read all query.
380      */

381     public boolean isReadAllQuery() {
382         return true;
383     }
384
385     /**
386      * INTERNAL:
387      * Prepare the receiver for execution in a session.
388      */

389     protected void prepare() throws QueryException {
390         super.prepare();
391
392         getContainerPolicy().prepare(this, getSession());
393
394         if (getContainerPolicy().overridesRead()) {
395             return;
396         }
397
398         prepareSelectAllRows();
399     }
400
401     /**
402      * INTERNAL:
403      * Set the properties needed to be cascaded into the custom query.
404      */

405     protected void prepareCustomQuery(DatabaseQuery customQuery) {
406         ReadAllQuery customReadQuery = (ReadAllQuery)customQuery;
407         customReadQuery.setContainerPolicy(getContainerPolicy());
408         customReadQuery.setCascadePolicy(getCascadePolicy());
409         customReadQuery.setShouldRefreshIdentityMapResult(shouldRefreshIdentityMapResult());
410         customReadQuery.setShouldMaintainCache(shouldMaintainCache());
411         customReadQuery.setShouldUseWrapperPolicy(shouldUseWrapperPolicy());
412     }
413
414     /**
415      * INTERNAL:
416      * Prepare the receiver for execution in a session.
417      */

418     public void prepareForExecution() throws QueryException {
419         super.prepareForExecution();
420
421         getContainerPolicy().prepareForExecution();
422
423     }
424
425     /**
426      * INTERNAL:
427      * Prepare the mechanism.
428      */

429     protected void prepareSelectAllRows() {
430         getQueryMechanism().prepareSelectAllRows();
431     }
432
433     /**
434      * INTERNAL:
435      * All objects queried via a UnitOfWork get registered here. If the query
436      * went to the database.
437      * <p>
438      * Involves registering the query result individually and in totality, and
439      * hence refreshing / conforming is done here.
440      *
441      * @param result may be collection (read all) or an object (read one),
442      * or even a cursor. If in transaction the shared cache will
443      * be bypassed, meaning the result may not be originals from the parent
444      * but raw database rows.
445      * @param unitOfWork the unitOfWork the result is being registered in.
446      * @param arguments the original arguments/parameters passed to the query
447      * execution. Used by conforming
448      * @param buildDirectlyFromRows If in transaction must construct
449      * a registered result from raw database rows.
450      *
451      * @return the final (conformed, refreshed, wrapped) UnitOfWork query result
452      */

453     public Object JavaDoc registerResultInUnitOfWork(Object JavaDoc result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) {
454         // For bug 2612366: Conforming results in UOW extremely slow.
455
// Replacing results with registered versions in the UOW is a part of
456
// conforming and is now done while conforming to maximize performance.
457
if (shouldConformResultsInUnitOfWork() || getDescriptor().shouldAlwaysConformResultsInUnitOfWork()) {
458             return conformResult(result, unitOfWork, arguments, buildDirectlyFromRows);
459         }
460
461         // When building directly from rows, one of the performance benefits
462
// is that we no longer have to wrap and then unwrap the originals.
463
// result is just a vector, not a collection of wrapped originals.
464
// Also for cursors the initial connection is automatically registered.
465
if (buildDirectlyFromRows) {
466             Vector rows = (Vector)result;
467             Set identitySet = null;
468             ContainerPolicy cp = getContainerPolicy();
469             Object JavaDoc clones = cp.containerInstance(rows.size());
470             for (Enumeration enumtr = rows.elements(); enumtr.hasMoreElements();) {
471                 Object JavaDoc row = enumtr.nextElement();
472
473                 // null is placed in the row collection for 1-m joining to filter duplicate rows.
474
if (row != null) {
475                     Object JavaDoc clone = registerIndividualResult(row, unitOfWork, buildDirectlyFromRows, null);
476
477                     // Avoid duplicates if -m joining was used and a cache hit occured.
478
if (getJoinedAttributeManager().isToManyJoin()) {
479                         if (identitySet == null) {
480                             identitySet = new TopLinkIdentityHashSet(rows.size());
481                         }
482                         if (!identitySet.contains(clone)) {
483                             identitySet.add(clone);
484                             cp.addInto(clone, clones, unitOfWork);
485                         }
486                     } else {
487                         cp.addInto(clone, clones, unitOfWork);
488                     }
489                 }
490             }
491             return clones;
492         }
493
494         ContainerPolicy cp;
495         cp = getContainerPolicy();
496
497         Object JavaDoc clones = cp.containerInstance(cp.sizeFor(result));
498         AbstractSession sessionToUse = unitOfWork.getParent();
499         for (Object JavaDoc iter = cp.iteratorFor(result); cp.hasNext(iter);) {
500             Object JavaDoc object = cp.next(iter, sessionToUse);
501             Object JavaDoc clone = registerIndividualResult(object, unitOfWork, buildDirectlyFromRows, null);
502             cp.addInto(clone, clones, unitOfWork);
503         }
504         return clones;
505     }
506
507     /**
508      * PUBLIC:
509      * Set the container policy. Used to support different containers
510      * (e.g. Collections, Maps).
511      */

512     public void setContainerPolicy(ContainerPolicy containerPolicy) {
513         // CR#... a container policy is always required, default is vector,
514
// required for deployment XML.
515
if (containerPolicy == null) {
516             return;
517         }
518         this.containerPolicy = containerPolicy;
519         setIsPrepared(false);
520     }
521
522     /**
523      * INTERNAL:
524      * Set the order expressions for the query.
525      */

526     public void setOrderByExpressions(Vector orderByExpressions) {
527         this.orderByExpressions = orderByExpressions;
528     }
529
530     /**
531      * PUBLIC:
532      * Configure the mapping to use an instance of the specified container class
533      * to hold the target objects.
534      * <p>jdk1.2.x: The container class must implement (directly or indirectly) the Collection interface.
535      * <p>jdk1.1.x: The container class must be a subclass of Vector.
536      */

537     public void useCollectionClass(Class JavaDoc concreteClass) {
538         // Set container policy.
539
setContainerPolicy(ContainerPolicy.buildPolicyFor(concreteClass));
540
541     }
542
543     /**
544      * PUBLIC:
545      * Configure the query to use an instance of the specified container class
546      * to hold the result objects. The key used to index the value in the Map
547      * is the value returned by a call to the specified zero-argument method.
548      * The method must be implemented by the class (or a superclass) of the
549      * value to be inserted into the Map.
550      * <p>jdk1.2.x: The container class must implement (directly or indirectly) the Map interface.
551      * <p>jdk1.1.x: The container class must be a subclass of Hashtable.
552      * <p>The referenceClass must set before calling this method.
553      */

554     public void useMapClass(Class JavaDoc concreteClass, String JavaDoc methodName) {
555         // the reference class has to be specified before coming here
556
if (getReferenceClass() == null) {
557             throw QueryException.referenceClassMissing(this);
558         }
559         ContainerPolicy policy = ContainerPolicy.buildPolicyFor(concreteClass);
560         policy.setKeyName(methodName, getReferenceClass().getName());
561         setContainerPolicy(policy);
562     }
563 }
564
Popular Tags