KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.queryframework;
23
24 import java.security.AccessController JavaDoc;
25 import java.security.PrivilegedActionException JavaDoc;
26 import java.util.*;
27 import oracle.toplink.essentials.internal.expressions.*;
28 import oracle.toplink.essentials.internal.helper.Helper;
29 import oracle.toplink.essentials.mappings.DatabaseMapping;
30 import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
31 import oracle.toplink.essentials.internal.security.PrivilegedClassForName;
32 import oracle.toplink.essentials.internal.sessions.MergeManager;
33 import oracle.toplink.essentials.exceptions.ValidationException;
34 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
35 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
36 import oracle.toplink.essentials.descriptors.ClassDescriptor;
37 import oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager;
38
39 /**
40  * <p><b>Purpose</b>:
41  * Abstract class for all read queries that build objects and potentially manipulate
42  * the TopLink cache.
43  *
44  * <p><b>Description</b>:
45  * Contains common behavior for all read queries building objects.
46  *
47  * @author Gordon Yorke
48  * @since TopLink Essentials
49  */

50 public abstract class ObjectBuildingQuery extends ReadQuery {
51
52     /** The class of the target objects to be read from the database. */
53     protected Class JavaDoc referenceClass;
54     protected String JavaDoc referenceClassName;
55
56     /** Allows for the resulting objects to be refresh with the data from the database. */
57     protected boolean shouldRefreshIdentityMapResult;
58     protected boolean shouldRefreshRemoteIdentityMapResult;
59
60     /** INTERNAL: for bug 2612601 allow ability not to register results in UOW. */
61     protected boolean shouldRegisterResultsInUnitOfWork = true;
62
63     /** CMP only. Allow users to configure whether finder should be executed in a uow or not. */
64     protected boolean shouldProcessResultsInUnitOfWork = true;
65
66     /** Used for pessimistic locking. */
67     protected ForUpdateClause lockingClause;
68     public static final short NO_LOCK = 0;
69     public static final short LOCK = 1;
70     public static final short LOCK_NOWAIT = 2;
71
72     // allow pessimistic locking policy to be used
73
public static final short DEFAULT_LOCK_MODE = -1;
74     protected boolean isPrePrepared;
75
76     /**
77      * Used to set the read time on objects that use this query.
78      * Should be set to the time the query returned from the database.
79      */

80     protected long executionTime = 0;
81
82     /**
83      * Added for Exclusive Connection (VPD) support see accessor for information
84      */

85     protected boolean shouldUseExclusiveConnection = false;
86
87     /**
88      * INTERNAL: This is the key for accessing unregistered and locked result in the query's properties.
89      * The uow and QueryBaseValueHolder use this property to record amd to retreive the result respectively.
90      */

91     public static final String JavaDoc LOCK_RESULT_PROPERTY = "LOCK_RESULT";
92
93     /** PERF: Store if the query originally used the default lock mode. */
94     protected boolean wasDefaultLockMode = false;
95     
96     /**
97      * INTERNAL:
98      * Initialize the state of the query
99      */

100     public ObjectBuildingQuery() {
101         this.shouldRefreshIdentityMapResult = false;
102     }
103
104     /**
105      * INTERNAL:
106      * Convert all the class-name-based settings in this query to actual class-based
107      * settings. This method is used when converting a project that has been built
108      * with class names to a project with classes.
109      * @param classLoader
110      */

111     public void convertClassNamesToClasses(ClassLoader JavaDoc classLoader){
112         super.convertClassNamesToClasses(classLoader);
113         Class JavaDoc referenceClass = null;
114         try{
115             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
116                 try {
117                     referenceClass = (Class JavaDoc)AccessController.doPrivileged(new PrivilegedClassForName(getReferenceClassName(), true, classLoader));
118                 } catch (PrivilegedActionException JavaDoc exception) {
119                     throw ValidationException.classNotFoundWhileConvertingClassNames(getReferenceClassName(), exception.getException());
120                 }
121             } else {
122                 referenceClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(getReferenceClassName(), true, classLoader);
123             }
124         } catch (ClassNotFoundException JavaDoc exc){
125             throw ValidationException.classNotFoundWhileConvertingClassNames(getReferenceClassName(), exc);
126         }
127         setReferenceClass(referenceClass);
128     };
129
130     /**
131      * INTERNAL:
132      * Return if this query originally used the default lock mode.
133      */

134     protected boolean wasDefaultLockMode() {
135         return wasDefaultLockMode;
136     }
137     
138     /**
139      * INTERNAL:
140      * Set if this query originally used the default lock mode.
141      */

142     protected void setWasDefaultLockMode(boolean wasDefaultLockMode) {
143         this.wasDefaultLockMode = wasDefaultLockMode;
144     }
145     
146     /**
147      * PUBLIC:
148      * When unset means perform read normally and dont do refresh.
149      */

150     public void dontRefreshIdentityMapResult() {
151         setShouldRefreshIdentityMapResult(false);
152     }
153
154     /**
155      * PUBLIC:
156      * When unset means perform read normally and dont do refresh.
157      */

158     public void dontRefreshRemoteIdentityMapResult() {
159         setShouldRefreshRemoteIdentityMapResult(false);
160     }
161
162     /**
163      * Return the fetch group set in the query.
164      * If a fetch group is not explicitly set in the query, default fetch group optionally defined in the decsiptor
165      * would be used, unless the user explicitly calls query.setShouldUseDefaultFetchGroup(false).
166      */

167     public FetchGroup getFetchGroup() {
168         return null;
169     }
170
171     /**
172      * PUBLIC:
173      * Return the current locking mode.
174      */

175     public short getLockMode() {
176         if (lockingClause == null) {
177             return DEFAULT_LOCK_MODE;
178         } else {
179             return lockingClause.getLockMode();
180         }
181     }
182
183     /**
184      * INTERNAL:
185      * Return all of the rows fetched by the query, used for 1-m joining.
186      */

187     public List getDataResults() {
188         return null;
189     }
190
191     /**
192      * INTERNAL:
193      * Return the time this query actually went to the database
194      */

195     public long getExecutionTime() {
196         return executionTime;
197     }
198
199     /**
200      * PUBLIC:
201      * Return the reference class of the query.
202      */

203     public Class JavaDoc getReferenceClass() {
204         return referenceClass;
205     }
206
207     /**
208      * INTERNAL:
209      * Return the reference class of the query.
210      */

211     public String JavaDoc getReferenceClassName() {
212         if ((referenceClassName == null) && (referenceClass != null)) {
213             referenceClassName = referenceClass.getName();
214         }
215         return referenceClassName;
216     }
217
218     /**
219      * INTERNAL:
220      * Return if partial attributes.
221      */

222     public boolean hasPartialAttributeExpressions() {
223         return false;
224     }
225
226     /**
227      * PUBLIC:
228      * Answers if the query lock mode is known to be LOCK or LOCK_NOWAIT.
229      *
230      * In the case of DEFAULT_LOCK_MODE and the query reference class being a CMP entity bean,
231      * at execution time LOCK, LOCK_NOWAIT, or NO_LOCK will be decided.
232      * <p>
233      * If a single joined attribute was configured for pessimistic locking then
234      * this will return true (after first execution) as the SQL contained a
235      * FOR UPDATE OF clause.
236      */

237     public boolean isLockQuery() {
238         return getLockMode() > NO_LOCK;
239     }
240
241     /**
242      * PUBLIC:
243      * Return if this is an object building query.
244      */

245     public boolean isObjectBuildingQuery() {
246         return true;
247     }
248
249     /**
250      * INTERNAL:
251      * Answers if we are executing through a UnitOfWork and registering results.
252      * This is only ever false if using the conforming without registering
253      * feature.
254      */

255     protected boolean isRegisteringResults() {
256         return ((shouldRegisterResultsInUnitOfWork() && getDescriptor().shouldRegisterResultsInUnitOfWork()) || isLockQuery());
257     }
258
259     /**
260      * PUBLIC:
261      * Refresh the attributes of the object(s) resulting from the query.
262      * If cascading is used the private parts of the objects will also be refreshed.
263      */

264     public void refreshIdentityMapResult() {
265         setShouldRefreshIdentityMapResult(true);
266     }
267
268     /**
269      * PUBLIC:
270      * Refresh the attributes of the object(s) resulting from the query.
271      * If cascading is used the private parts of the objects will also be refreshed.
272      */

273     public void refreshRemoteIdentityMapResult() {
274         setShouldRefreshRemoteIdentityMapResult(true);
275     }
276
277     /**
278      * INTERNAL:
279      * Constructs the final (registered) object for every individual object
280      * queried via a UnitOfWork.
281      * <p>
282      * Called for every object in a read all, the object in a read object, and
283      * every time the next or previous row is retrieved from a cursor.
284      * <p>
285      * The (conform) without registering feature is implemented here, and may
286      * return an original non UnitOfWork registered result.
287      * <p>
288      * Pessimistically locked objects are tracked here.
289      *
290      * @param result may be an object (in the identity map of the parent session),
291      * which becomes the original, or a raw database row if in transaction.
292      * @param buildDirectlyFromRows true if must construct
293      * a registered result from raw database rows.
294      *
295      * @return a refreshed UnitOfWork queried object, unwrapped.
296      */

297     public Object JavaDoc registerIndividualResult(Object JavaDoc result, UnitOfWorkImpl unitOfWork, boolean buildDirectlyFromRows, JoinedAttributeManager joinManager) {
298         Object JavaDoc clone = null;
299         if (buildDirectlyFromRows) {
300             // This method will either call back later with buildDirectlyFromRows == false,
301
// or special code which builds/refreshes clones directly from the
302
// row will be invoked.
303
return buildObject((AbstractRecord)result);
304         }
305         // For bug 2612601 Conforming without registering in Unit Of Work.
306
else if (!isRegisteringResults()) {
307             clone = unitOfWork.getIdentityMapAccessorInstance().getIdentityMapManager().getFromIdentityMap(result);
308
309             // If object not registered do not register it here! Simply return
310
// the original to the user.
311
// Avoid setting clone = original, in case revert(clone) is called.
312
if (clone == null) {
313                 clone = result;
314             }
315         } else {
316             // bug # 3183379 either the object comes from the shared cache and is existing, or
317
//it is from a parent unit of work and this unit of work does not need to know if it is new
318
//or not. It will query the parent unit of work to determine newness.
319
clone = unitOfWork.registerExistingObject(result, joinManager);
320         }
321
322         // Check for refreshing, require to revert in the unit of work to accomplish a refresh.
323
if (shouldRefreshIdentityMapResult()) {
324             // Revert only works in the object is in the parent cache, if it is not merge must be used.
325
if (unitOfWork.getParent().getIdentityMapAccessor().containsObjectInIdentityMap(clone)) {
326                 if (shouldCascadeAllParts()) {
327                     unitOfWork.deepRevertObject(clone);
328                 } else if (shouldCascadePrivateParts()) {
329                     unitOfWork.revertObject(clone);
330                 } else if (shouldCascadeByMapping()) {
331                     unitOfWork.revertObject(clone, MergeManager.CASCADE_BY_MAPPING);
332                 } else if (!shouldCascadeParts()) {
333                     unitOfWork.shallowRevertObject(clone);
334                 }
335             } else {
336                 if (shouldCascadeAllParts()) {
337                     unitOfWork.deepMergeClone(result);
338                 } else if (shouldCascadePrivateParts()) {
339                     unitOfWork.mergeClone(result);
340                 } else if (shouldCascadeByMapping()) {
341                     unitOfWork.mergeClone(result, MergeManager.CASCADE_BY_MAPPING);
342                 } else if (!shouldCascadeParts()) {
343                     unitOfWork.shallowMergeClone(result);
344                 }
345             }
346         }
347
348         // record clone if referenced class has pessimistic locking policy
349
recordCloneForPessimisticLocking(clone, unitOfWork);
350
351         return clone;
352     }
353
354     /**
355      * INTERNAL:
356      * Set the the time this query went to the database.
357      */

358     public void setExecutionTime(long executionTime) {
359         this.executionTime = executionTime;
360     }
361
362     /**
363      * PUBLIC:
364      * Sets whether this is a pessimistically locking query.
365      * <ul>
366      * <li>ObjectBuildingQuery.LOCK: SELECT .... FOR UPDATE issued.
367      * <li>ObjectBuildingQuery.LOCK_NOWAIT: SELECT .... FOR UPDATE NO WAIT issued.
368      * <li>ObjectBuildingQuery.NO_LOCK: no pessimistic locking.
369      * <li>ObjectBuildingQuery.DEFAULT_LOCK_MODE (default) and you have a CMP descriptor:
370      * fine grained locking will occur.
371      * </ul>
372      * <p>Fine Grained Locking: On execution the reference class
373      * and those of all joined attributes will be checked. If any of these have a
374      * PessimisticLockingPolicy set on their descriptor, they will be locked in a
375      * SELECT ... FOR UPDATE OF ... {NO WAIT}. Issues fewer locks
376      * and avoids setting the lock mode on each query.
377      * <p>Example:<code>readAllQuery.setSelectionCriteria(employee.get("address").equal("Ottawa"));</code>
378      * <ul><li>LOCK: all employees in Ottawa and all referenced Ottawa addresses will be locked.
379      * <li>DEFAULT_LOCK_MODE: if address is a joined attribute, and only address has a pessimistic
380      * locking policy, only referenced Ottawa addresses will be locked.
381      * </ul>
382      * @see oracle.toplink.essentials.descriptors.PessimisticLockingPolicy
383      */

384     public void setLockMode(short lockMode) {
385         lockingClause = ForUpdateClause.newInstance(lockMode);
386     }
387
388     /**
389      * REQUIRED:
390      * Set the reference class for the query.
391      */

392     public void setReferenceClass(Class JavaDoc aClass) {
393         referenceClass = aClass;
394         setIsPrepared(false);
395     }
396
397     /**
398      * INTERNAL:
399      * Set the reference class for the query.
400      */

401     public void setReferenceClassName(String JavaDoc aClass) {
402         referenceClassName = aClass;
403         setIsPrepared(false);
404     }
405
406     /**
407      * PUBLIC:
408      * Set if the attributes of the object(s) resulting from the query should be refreshed.
409      * If cascading is used the private parts of the objects will also be refreshed.
410      */

411     public void setShouldRefreshIdentityMapResult(boolean shouldRefreshIdentityMapResult) {
412         this.shouldRefreshIdentityMapResult = shouldRefreshIdentityMapResult;
413         if (shouldRefreshIdentityMapResult) {
414             setShouldRefreshRemoteIdentityMapResult(true);
415         }
416     }
417
418     /**
419      * PUBLIC:
420      * Set if the attributes of the object(s) resulting from the query should be refreshed.
421      * If cascading is used the private parts of the objects will also be refreshed.
422      */

423     public void setShouldRefreshRemoteIdentityMapResult(boolean shouldRefreshIdentityMapResult) {
424         this.shouldRefreshRemoteIdentityMapResult = shouldRefreshIdentityMapResult;
425     }
426
427     /**
428      * INTERNAL:
429      * Set to false to have queries conform to a UnitOfWork without registering
430      * any additional objects not already in that UnitOfWork.
431      * @see #shouldRegisterResultsInUnitOfWork
432      * @bug 2612601
433      */

434     public void setShouldRegisterResultsInUnitOfWork(boolean shouldRegisterResultsInUnitOfWork) {
435         this.shouldRegisterResultsInUnitOfWork = shouldRegisterResultsInUnitOfWork;
436     }
437
438     /**
439      * INTERNAL:
440      * Allows one to do conforming in a UnitOfWork without registering.
441      * Queries executed on a UnitOfWork will only return working copies for objects
442      * that have already been registered.
443      * <p>Extreme care should be taken in using this feature, for a user will
444      * get back a mix of registered and original (unregistered) objects.
445      * <p>Best used with a WrapperPolicy where invoking on an object will trigger
446      * its registration (CMP). Without a WrapperPolicy {@link oracle.toplink.essentials.sessions.UnitOfWork#registerExistingObject registerExistingObject}
447      * should be called on any object that you intend to change.
448      * @return true by default.
449      * @see #setShouldRegisterResultsInUnitOfWork
450      * @see oracle.toplink.essentials.publicinterface.Descriptor#shouldRegisterResulstInUnitOfWork
451      * @bug 2612601
452      */

453     public boolean shouldRegisterResultsInUnitOfWork() {
454         return shouldRegisterResultsInUnitOfWork;
455     }
456
457     /**
458      * INTERNAL:
459      * Return if this is a full object query, not partial nor fetch group.
460      */

461     public boolean shouldReadAllMappings() {
462         return true;
463     }
464     
465     /**
466      * INTERNAL:
467      * Check if the mapping is part of the partial attributes.
468      */

469     public boolean shouldReadMapping(DatabaseMapping mapping) {
470         return true;
471     }
472
473     /**
474      * PUBLIC:
475      * Set to a boolean. When set means refresh the instance
476      * variables of referenceObject from the database.
477      */

478     public boolean shouldRefreshIdentityMapResult() {
479         return shouldRefreshIdentityMapResult;
480     }
481
482     /**
483      * PUBLIC:
484      * Set to a boolean. When set means refresh the instance
485      * variables of referenceObject from the database.
486      */

487     public boolean shouldRefreshRemoteIdentityMapResult() {
488         return shouldRefreshRemoteIdentityMapResult;
489     }
490
491     public String JavaDoc toString() {
492         if (getReferenceClass() == null) {
493             return super.toString();
494         }
495         return Helper.getShortClassName(getClass()) + "(" + getReferenceClass().getName() + ")";
496     }
497
498     /**
499      * ADVANCED:
500      * Used for CMP only. This allows users to indicate whether cmp finders executed
501      * at the beginning of a transaction should always be run against a UnitOfWork.
502      * Defaults to true.
503      * <p>
504      * If set to false, then UnitOfWork allocation will be deferred until a business
505      * method (including creates/removes) or finder with shouldProcessResultsInUnitOfWork == true
506      * is invoked. Any finder executed before such a time, will do so against the
507      * underlying ServerSession. Forcing finder execution to always go through a
508      * UnitOfWork means the results will be cloned and cached in the UnitOfWork up
509      * front. This is desired when the results will be accessed in the same transaction.
510      * <p>
511      * Note that finders executed with an unspecified transaction context will never
512      * be executed against a UnitOfWork, even if this setting is true. This case may happen
513      * with the NotSupported, Never, and Supports attributes.
514      */

515     public void setShouldProcessResultsInUnitOfWork(boolean processResultsInUnitOfWork) {
516         this.shouldProcessResultsInUnitOfWork = processResultsInUnitOfWork;
517     }
518
519     /**
520      * ADVANCED:
521      * Used for CMP only. Indicates whether cmp finders executed at the beginning
522      * of a transaction should always be run against a UnitOfWork.
523      * Defaults to true.
524      * <p>
525      * If set to false, then UnitOfWork allocation will be deferred until a business
526      * method (including creates/removes) or finder with shouldProcessResultsInUnitOfWork == true
527      * is invoked. Any finder executed before such a time, will do so against the
528      * underlying ServerSession. Forcing finder execution to always go through a
529      * UnitOfWork means the results will be cloned and cached in the UnitOfWork up
530      * front. This is desired when the results will be accessed in the same transaction.
531      * <p>
532      * Note that finders executed with an unspecified transaction context will never
533      * be executed against a UnitOfWork, even if this setting is true. This case may happen
534      * with the NotSupported, Never, and Supports attributes.
535      */

536     public boolean shouldProcessResultsInUnitOfWork() {
537         return this.shouldProcessResultsInUnitOfWork;
538     }
539
540     /**
541      * INTERNAL:
542      * Return if the attribute is specified for joining.
543      */

544     public boolean isAttributeJoined(ClassDescriptor mappingDescriptor, String JavaDoc attributeName) {
545         return false;
546     }
547
548     /**
549     * INTERNAL:
550     * Helper method that checks if clone has been locked with uow.
551     */

552     public boolean isClonePessimisticLocked(Object JavaDoc clone, UnitOfWorkImpl uow) {
553         return false;
554     }
555
556     /**
557      * INTERNAL:
558      * Helper method that records clone with uow if query is pessimistic locking.
559      */

560     public void recordCloneForPessimisticLocking(Object JavaDoc clone, UnitOfWorkImpl uow) {
561         if ((isLockQuery()) && lockingClause.isReferenceClassLocked()) {
562             uow.addPessimisticLockedClone(clone);
563         }
564     }
565
566     /**
567     * INTERNAL: Helper method to determine the default mode. If true and quey has a pessimistic locking policy,
568     * locking will be configured according to the pessimistic locking policy.
569     */

570     public boolean isDefaultLock() {
571         return (lockingClause == null);
572     }
573
574 }
575
Popular Tags