KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > descriptors > VersionLockingPolicy


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.descriptors;
23
24 import java.math.*;
25 import java.io.*;
26 import java.util.*;
27 import oracle.toplink.essentials.mappings.*;
28 import oracle.toplink.essentials.internal.helper.*;
29 import oracle.toplink.essentials.queryframework.*;
30 import oracle.toplink.essentials.expressions.*;
31 import oracle.toplink.essentials.exceptions.*;
32 import oracle.toplink.essentials.internal.descriptors.OptimisticLockingPolicy;
33 import oracle.toplink.essentials.internal.sessions.ObjectChangeSet;
34 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
35 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
36 import oracle.toplink.essentials.internal.sessions.AbstractSession;
37
38 /**
39  * <p><b>Purpose</b>: Used to allow a single version number to be used for optimistic locking.
40  *
41  * @since TOPLink/Java 2.0
42  */

43 public class VersionLockingPolicy implements OptimisticLockingPolicy, Serializable {
44     protected DatabaseField writeLockField;
45     protected int lockValueStored;
46     protected ClassDescriptor descriptor;
47     protected transient Expression cachedExpression;
48     public final static int IN_CACHE = 1;
49     public final static int IN_OBJECT = 2;
50
51     /**
52      * PUBLIC:
53      * Create a new VersionLockingPolicy. Defaults to
54      * storing the lock value in the cache.
55      */

56     public VersionLockingPolicy() {
57         super();
58         storeInCache();
59     }
60
61     /**
62      * PUBLIC:
63      * Create a new VersionLockingPolicy. Defaults to
64      * storing the lock value in the cache.
65      * @param fieldName specifies the field name for the write
66      * lock field.
67      */

68     public VersionLockingPolicy(String JavaDoc fieldName) {
69         this(new DatabaseField(fieldName));
70     }
71
72     /**
73      * PUBLIC:
74      * Create a new VersionLockingPolicy. Defaults to
75      * storing the lock value in the cache.
76      * @param the write lock field.
77      */

78     public VersionLockingPolicy(DatabaseField field) {
79         this();
80         setWriteLockField(field);
81     }
82
83     /**
84      * INTERNAL:
85      * Add update fields for template row.
86      * These are any unmapped fields required to write in an update.
87      */

88     public void addLockFieldsToUpdateRow(AbstractRecord databaseRow, AbstractSession session) {
89         if (isStoredInCache()) {
90             databaseRow.put(getWriteLockField(), null);
91         }
92     }
93
94     /**
95      * INTERNAL:
96      * This method adds the lock value to the translation row of the
97      * passed in query. depending on the storage flag, the value is
98      * either retrieved from the cache of the object.
99      */

100     public void addLockValuesToTranslationRow(ObjectLevelModifyQuery query) {
101         Object JavaDoc value;
102         if (isStoredInCache()) {
103             value = query.getSession().getIdentityMapAccessor().getWriteLockValue(query.getPrimaryKey(), query.getObject().getClass());
104         } else {
105             value = lockValueFromObject(query.getObject());
106         }
107         if (value == null) {
108             if (query.isDeleteObjectQuery()) {
109                 throw OptimisticLockException.noVersionNumberWhenDeleting(query.getObject(), query);
110             } else {
111                 throw OptimisticLockException.noVersionNumberWhenUpdating(query.getObject(), query);
112             }
113         }
114         query.getTranslationRow().put(getWriteLockField(), value);
115     }
116
117     /**
118      * INTERNAL:
119      * When given an expression, this method will return a new expression with
120      * the optimistic locking values included. The values are taken from the
121      * passed in database row. This expression will be used in a delete call.
122      */

123     public Expression buildDeleteExpression(DatabaseTable table, Expression mainExpression, AbstractRecord row) {
124         //use the same expression as update
125
return buildUpdateExpression(table, mainExpression, row, null);
126     }
127
128     /**
129      * INTERNAL:
130      * Returns an expression that will be used for both the update and
131      * delete where clause
132      */

133     protected Expression buildExpression() {
134         ExpressionBuilder builder = new ExpressionBuilder();
135
136         return builder.getField(getWriteLockField()).equal(builder.getParameter(getWriteLockField()));
137     }
138
139     /**
140      * INTERNAL:
141      * When given an expression, this method will return a new expression
142      * with the optimistic locking values included. The values are taken
143      * from the passed in database row. This expression will be used in
144      * an update call.
145      */

146     public Expression buildUpdateExpression(DatabaseTable table, Expression mainExpression, AbstractRecord row, AbstractRecord row2) {
147         if (cachedExpression == null) {
148             cachedExpression = buildExpression();
149         }
150         if (getWriteLockField().getTableName().equals(table.getName())) {
151             return mainExpression.and(cachedExpression);
152         }
153         return mainExpression;
154     }
155
156     /**
157      * INTERNAL:
158      * Clone the policy
159      */

160     public Object JavaDoc clone() {
161         try {
162             return super.clone();
163         } catch (CloneNotSupportedException JavaDoc e) {
164             return null;
165         }
166     }
167
168     /**
169      * INTERNAL:
170      * This method compares two writeLockValues.
171      * The writeLockValues should be non-null and of type Number.
172      * Returns:
173      * -1 if value1 is less (older) than value2;
174      * 0 if value1 equals value2;
175      * 1 if value1 is greater (newer) than value2.
176      * Throws:
177      * NullPointerException if the passed value is null;
178      * ClassCastException if the passed value is of a wrong type.
179      */

180     public int compareWriteLockValues(Object JavaDoc value1, Object JavaDoc value2) {
181         BigDecimal bigDecimalValue1, bigDecimalValue2;
182         if(value1 instanceof BigDecimal) {
183             bigDecimalValue1 = (BigDecimal)value1;
184         } else {
185             bigDecimalValue1 = new BigDecimal(((Number JavaDoc)value1).longValue());
186         }
187         if(value2 instanceof BigDecimal) {
188             bigDecimalValue2 = (BigDecimal)value2;
189         } else {
190             bigDecimalValue2 = new BigDecimal(((Number JavaDoc)value2).longValue());
191         }
192         return bigDecimalValue1.compareTo(bigDecimalValue2);
193     }
194
195     /**
196      * INTERNAL:
197
198      * Return the default version locking filed java type, default is BigDecimal
199
200      */

201     protected Class JavaDoc getDefaultLockingFieldType() {
202         return ClassConstants.BIGDECIMAL;
203
204     }
205
206     /**
207      * INTERNAL:
208      * This is the base value that is older than all other values, it is used in the place of
209      * null in some situations.
210      */

211     public Object JavaDoc getBaseValue() {
212         return new BigDecimal(0);
213     }
214
215     /**
216      * INTERNAL:
217      */

218     protected ClassDescriptor getDescriptor() {
219         return descriptor;
220     }
221
222     /**
223      * INTERNAL:
224      * returns the initial locking value
225      */

226     protected Object JavaDoc getInitialWriteValue(AbstractSession session) {
227         return new BigDecimal(1);
228     }
229
230     /**
231      * INTERNAL:
232      * This method gets the write lock value from either the cache or
233      * the object stored in the query. It then returns the new incremented value.
234      */

235     protected Object JavaDoc getNewLockValue(ModifyQuery query) {
236         Class JavaDoc objectClass = query.getDescriptor().getJavaClass();
237         Number JavaDoc value;
238         Number JavaDoc newWriteLockValue = null;
239         if (isStoredInCache()) {
240             value = (Number JavaDoc)query.getSession().getIdentityMapAccessor().getWriteLockValue(((WriteObjectQuery)query).getPrimaryKey(), objectClass);
241         } else {
242             value = (Number JavaDoc)lockValueFromObject(((ObjectLevelModifyQuery)query).getObject());
243         }
244         if (value == null) {
245             throw oracle.toplink.essentials.exceptions.OptimisticLockException.noVersionNumberWhenUpdating(((ObjectLevelModifyQuery)query).getObject(), (ObjectLevelModifyQuery)query);
246         }
247
248         // Increment the value, this goes to the database
249
newWriteLockValue = incrementWriteLockValue(value);
250         return newWriteLockValue;
251     }
252
253     /**
254      * INTERNAL:
255      * This method returns any of the fields that are not mapped in
256      * the object. In the case of the value being stored in the
257      * cache, a vector with one value is returned. In the case
258      * of being stored in the object, an empty vector is returned.
259      */

260     protected Vector getUnmappedFields() {
261         Vector fields = new Vector(1);
262         if (isStoredInCache()) {
263             fields.addElement(getWriteLockField());
264         }
265         return fields;
266     }
267
268     /**
269      * INTERNAL:
270      * Return the value that should be stored in the identity map.
271      * If the value is stored in the object, then return a null.
272      */

273     public Object JavaDoc getValueToPutInCache(AbstractRecord row, AbstractSession session) {
274         if (isStoredInCache()) {
275             return row.get(getWriteLockField());
276         } else {
277             return null;
278         }
279     }
280
281     /**
282      * PUBLIC:
283      * Return the number of versions different between these objects.
284      * @param currentValue the new lock value
285      * @param domainObject the object containing the version to be compared to
286      * @param primaryKeys a vector containing the primary keys of the domainObject
287      * @param session the session to be used with the comparison
288      */

289     public int getVersionDifference(Object JavaDoc currentValue, Object JavaDoc domainObject, Vector primaryKeys, AbstractSession session) {
290         Number JavaDoc writeLockFieldValue;
291         Number JavaDoc newWriteLockFieldValue = (Number JavaDoc)currentValue;
292
293         // 2.5.1.6 if the write lock value is null, then what ever we have is treated as newer.
294
if (newWriteLockFieldValue == null) {
295             return 0;//merge it as either the object is new or being forced merged.
296
}
297
298         if (isStoredInCache()) {
299             writeLockFieldValue = (Number JavaDoc)session.getIdentityMapAccessor().getWriteLockValue(primaryKeys, domainObject.getClass());
300         } else {
301             writeLockFieldValue = (Number JavaDoc)lockValueFromObject(domainObject);
302         }
303         if (writeLockFieldValue == null) {
304             writeLockFieldValue = new BigDecimal(0);// the object is not in the cache so assume this is a new object
305
}
306         if (!(writeLockFieldValue instanceof BigDecimal)) {
307             writeLockFieldValue = new BigDecimal(writeLockFieldValue.longValue());
308         }
309         if (!(newWriteLockFieldValue instanceof BigDecimal)) {
310             newWriteLockFieldValue = new BigDecimal(newWriteLockFieldValue.longValue());
311         }
312         return ((BigDecimal)newWriteLockFieldValue).subtract((BigDecimal)writeLockFieldValue).intValue();
313     }
314
315     /**
316        * INTERNAL:
317        * Return the write lock field.
318        */

319     public DatabaseField getWriteLockField() {
320         return writeLockField;
321     }
322
323     /**
324      * PUBLIC:
325      * Return the field name of the field that stores the write lock value.
326      */

327     public String JavaDoc getWriteLockFieldName() {
328         return getWriteLockField().getQualifiedName();
329     }
330
331     /**
332      * INTERNAL:
333      * Retrun an expression that updates the write lock
334      */

335     public Expression getWriteLockUpdateExpression(ExpressionBuilder builder) {
336         return ExpressionMath.add(builder.getField(writeLockField.getName()), 1);
337     }
338
339     /**
340      * INTERNAL:
341      * This method will return the optimistic lock value for the object
342      */

343     public Object JavaDoc getWriteLockValue(Object JavaDoc domainObject, java.util.Vector JavaDoc primaryKey, AbstractSession session) {
344         Number JavaDoc writeLockFieldValue;
345         if (isStoredInCache()) {
346             writeLockFieldValue = (Number JavaDoc)session.getIdentityMapAccessor().getWriteLockValue(primaryKey, domainObject.getClass());
347         } else {
348             writeLockFieldValue = (Number JavaDoc)lockValueFromObject(domainObject);
349         }
350         return writeLockFieldValue;
351     }
352
353     /**
354      * INTERNAL:
355      * adds 1 to the value passed in
356      */

357     protected Number JavaDoc incrementWriteLockValue(Number JavaDoc numberValue) {
358         BigDecimal writeLockValue;
359
360         if (numberValue instanceof BigDecimal) {
361             writeLockValue = (BigDecimal)numberValue;
362         } else {
363             writeLockValue = new BigDecimal(numberValue.doubleValue());
364         }
365
366         return writeLockValue.add(new BigDecimal(1));
367     }
368
369     /**
370      * INTERNAL:
371      * It is responsible for initializing the policy;
372      */

373     public void initialize(AbstractSession session) {
374         DatabaseMapping mapping = mappingFromLockField();
375         if (mapping == null) {
376             if (isStoredInObject()) {
377                 throw OptimisticLockException.mustHaveMappingWhenStoredInObject(descriptor.getJavaClass());
378             } else {
379                 return;
380             }
381         }
382         if (mapping.isReadOnly()) {
383             throw DescriptorException.mappingCanNotBeReadOnly(mapping);
384         } else {
385             if (isStoredInCache()) {
386                 session.getIntegrityChecker().handleError(DescriptorException.mustBeReadOnlyMappingWhenStoredInCache(mapping));
387             }
388         }
389     }
390
391     /**
392      * INTERNAL:
393      * It is responsible for initializing the policy properties;
394      */

395     public void initializeProperties() {
396         DatabaseField dbField = getWriteLockField();
397
398         descriptor.buildField(dbField);
399         if (dbField.getType() == null) {
400             //set the default type
401
dbField.setType(getDefaultLockingFieldType());
402
403         }
404         Enumeration enumtr = this.getUnmappedFields().elements();
405         while (enumtr.hasMoreElements()) {
406             DatabaseField lockField;
407             lockField = (DatabaseField)enumtr.nextElement();
408             descriptor.getFields().addElement(lockField);
409         }
410     }
411
412     /**
413      * INTERNAL:
414      * Update the parent write lock value if the unit of works has been incremented.
415      */

416     public boolean isChildWriteLockValueGreater(AbstractSession session, java.util.Vector JavaDoc primaryKey, Class JavaDoc original, ObjectChangeSet changeSet) {
417         if (isStoredInCache()) {
418             // If this uow changed the object the version must be updated,
419
// we can check this by ensuring our value is greater than our parent's.
420
Number JavaDoc writeLockValue = (Number JavaDoc)changeSet.getWriteLockValue();
421             Number JavaDoc parentValue = (Number JavaDoc)session.getIdentityMapAccessor().getWriteLockValue(primaryKey, original);
422             if ((parentValue != null) && (!(parentValue instanceof BigDecimal))) {
423                 parentValue = new BigDecimal(parentValue.longValue());
424             }
425             if ((writeLockValue != null) && (!(writeLockValue instanceof BigDecimal))) {
426                 writeLockValue = new BigDecimal(writeLockValue.longValue());
427             }
428             if (writeLockValue != null) {// This occurs if the object was deleted
429
if ((parentValue == null) || (((BigDecimal)parentValue).compareTo((BigDecimal)writeLockValue) == -1)) {
430                     return true;
431                 }
432             }
433         }
434         return false;
435     }
436
437     /**
438      * INTERNAL:
439      * Update the parent write lock value if the unit of works has been incremented.
440      */

441     public boolean isChildWriteLockValueGreater(UnitOfWorkImpl uow, java.util.Vector JavaDoc primaryKey, Class JavaDoc original) {
442         if (isStoredInCache()) {
443             // If this uow changed the object the version must be updated,
444
// we can check this by ensuring our value is greater than our parent's.
445
Number JavaDoc writeLockValue = (Number JavaDoc)uow.getIdentityMapAccessor().getWriteLockValue(primaryKey, original);
446             Number JavaDoc parentValue = (Number JavaDoc)uow.getParent().getIdentityMapAccessor().getWriteLockValue(primaryKey, original);
447             if ((parentValue != null) && (!(parentValue instanceof BigDecimal))) {
448                 parentValue = new BigDecimal(parentValue.longValue());
449             }
450             if ((writeLockValue != null) && (!(writeLockValue instanceof BigDecimal))) {
451                 writeLockValue = new BigDecimal(writeLockValue.longValue());
452             }
453             if (writeLockValue != null) {// This occurs if the object was deleted
454
if ((parentValue == null) || (((BigDecimal)parentValue).compareTo((BigDecimal)writeLockValue) == -1)) {
455                     return true;
456                 }
457             }
458         }
459         return false;
460     }
461
462     /**
463      * INTERNAL:
464      * Compares the value with the value from the object (or cache).
465      * Will return true if the object is newer.
466      */

467     public boolean isNewerVersion(Object JavaDoc currentValue, Object JavaDoc domainObject, java.util.Vector JavaDoc primaryKey, AbstractSession session) {
468         Number JavaDoc writeLockFieldValue;
469         Number JavaDoc newWriteLockFieldValue = (Number JavaDoc)currentValue;
470
471         // 2.5.1.6 if the write lock value is null, then what ever we have is treated as newer.
472
if (newWriteLockFieldValue == null) {
473             return true;
474         }
475
476         if (isStoredInCache()) {
477             writeLockFieldValue = (Number JavaDoc)session.getIdentityMapAccessor().getWriteLockValue(primaryKey, domainObject.getClass());
478         } else {
479             writeLockFieldValue = (Number JavaDoc)lockValueFromObject(domainObject);
480         }
481         if (!(writeLockFieldValue instanceof BigDecimal)) {
482             writeLockFieldValue = new BigDecimal(writeLockFieldValue.longValue());
483         }
484         if (!(newWriteLockFieldValue instanceof BigDecimal)) {
485             newWriteLockFieldValue = new BigDecimal(newWriteLockFieldValue.longValue());
486         }
487         if ((writeLockFieldValue != null) && (((BigDecimal)newWriteLockFieldValue).compareTo((BigDecimal)writeLockFieldValue) != 1)) {
488             return false;
489         }
490         return true;
491     }
492
493     /**
494      * INTERNAL:
495      * Compares the value from the row and from the object (or cache).
496      * Will return true if the object is newer than the row.
497      */

498     public boolean isNewerVersion(AbstractRecord databaseRow, Object JavaDoc domainObject, java.util.Vector JavaDoc primaryKey, AbstractSession session) {
499         Number JavaDoc writeLockFieldValue;
500         Number JavaDoc newWriteLockFieldValue = (Number JavaDoc)databaseRow.get(getWriteLockField());
501         if (isStoredInCache()) {
502             writeLockFieldValue = (Number JavaDoc)session.getIdentityMapAccessor().getWriteLockValue(primaryKey, domainObject.getClass());
503         } else {
504             writeLockFieldValue = (Number JavaDoc)lockValueFromObject(domainObject);
505         }
506         if (!(writeLockFieldValue instanceof BigDecimal)) {
507             writeLockFieldValue = new BigDecimal(writeLockFieldValue.longValue());
508         }
509         if (!(newWriteLockFieldValue instanceof BigDecimal)) {
510             newWriteLockFieldValue = new BigDecimal(newWriteLockFieldValue.longValue());
511         }
512         if ((writeLockFieldValue != null) && (((BigDecimal)newWriteLockFieldValue).compareTo((BigDecimal)writeLockFieldValue) != 1)) {
513             return false;
514         }
515         return true;
516     }
517
518     /**
519      * PUBLIC:
520      * Return true if the lock value is stored in the cache.
521      */

522     public boolean isStoredInCache() {
523         return lockValueStored == IN_CACHE;
524     }
525
526     /**
527      * PUBLIC:
528      * Return true if the lock value is stored in the object.
529      */

530     public boolean isStoredInObject() {
531         return lockValueStored == IN_OBJECT;
532     }
533
534     /**
535      * INTERNAL:
536      * retrieves the lock value from the object.
537      */

538     protected Object JavaDoc lockValueFromObject(Object JavaDoc domainObject) {
539         return getDescriptor().getObjectBuilder().getBaseValueForField(getWriteLockField(), domainObject);
540     }
541
542     /**
543      * INTERNAL:
544      * returns the mapping from the writelock field.
545      * returns null if not found
546      */

547     protected DatabaseMapping mappingFromLockField() {
548         return descriptor.getObjectBuilder().getMappingForField(getWriteLockField());
549     }
550
551     /**
552      * INTERNAL:
553      * Only applicable when the value is stored in the cache. Will merge with the parent unit of work.
554      */

555     public void mergeIntoParentCache(UnitOfWorkImpl uow, Vector primaryKey, Object JavaDoc object) {
556         if (isStoredInCache()) {
557             Object JavaDoc parentValue = uow.getParent().getIdentityMapAccessor().getWriteLockValue(primaryKey, object.getClass());
558             uow.getIdentityMapAccessor().updateWriteLockValue(primaryKey, object.getClass(), parentValue);
559         }
560     }
561
562     /**
563      * INTERNAL:
564      */

565     public void setDescriptor(ClassDescriptor descriptor) {
566         this.descriptor = descriptor;
567     }
568
569     /**
570      * PUBLIC:
571      * Set whether to store the lock in the cache or in the object.
572      * @param isStoredInCache set this to true if you would like to store lock in the cache and set it
573      * to false if you would like to store it in the object.
574      */

575     public void setIsStoredInCache(boolean isStoredInCache) {
576         if (isStoredInCache) {
577             storeInCache();
578         } else {
579             storeInObject();
580         }
581     }
582
583     /**
584      * INTERNAL:
585      * This method must be included in any locking policy.
586      * Put the initial writelock value into the modifyRow.
587      */

588     public void setupWriteFieldsForInsert(ObjectLevelModifyQuery query) {
589         Object JavaDoc lockValue = getInitialWriteValue(query.getSession());
590         ObjectChangeSet objectChangeSet = query.getObjectChangeSet();
591         if (objectChangeSet != null) {
592             objectChangeSet.setInitialWriteLockValue(lockValue);
593         }
594         updateWriteLockValueForWrite(query, lockValue);
595     }
596
597     /**
598      * INTERNAL:
599      * Update the row, object and change set with the version value.
600      * This handles the version being mapped in nested aggregates, writable or read-only.
601      */

602     protected void updateWriteLockValueForWrite(ObjectLevelModifyQuery query, Object JavaDoc lockValue) {
603         query.getModifyRow().put(getWriteLockField(), lockValue);
604         ObjectChangeSet objectChangeSet = query.getObjectChangeSet();
605         if (objectChangeSet != null) {
606             objectChangeSet.setWriteLockValue(lockValue);
607         }
608
609         // CR#3173211
610
// If the value is stored in the cache or object, there still may
611
// be read-only mappings for it, so the object must always be updated for
612
// any writable or read-only mappings for the version value.
613
// Reuse the method used for returning as has the same requirements.
614
AbstractRecord record = getDescriptor().getObjectBuilder().createRecord(1);
615         record.put(getWriteLockField(), lockValue);
616         getDescriptor().getObjectBuilder().assignReturnRow(query.getObject(), query.getSession(), record);
617         if (query.getSession().isUnitOfWork() && (((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet() != null)) {
618             if (objectChangeSet == null) {
619                 // For aggregate collections the change set may be null, as they use the old commit still.
620
objectChangeSet = (ObjectChangeSet)((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet().getObjectChangeSetForClone(query.getObject());
621             }
622             query.getQueryMechanism().updateChangeSet(getDescriptor(), objectChangeSet, record, query.getObject());
623         }
624     }
625
626     /**
627      * ADVANCED:
628      * Set the write lock field.
629      * This can be used for advanced field types, such as XML nodes, or to set the field type.
630      */

631     public void setWriteLockField(DatabaseField writeLockField) {
632         this.writeLockField = writeLockField;
633     }
634
635     /**
636      * PUBLIC:
637      * Set the write lock field name.
638      * @param writeLockFieldName the name of the field to lock against.
639      */

640     public void setWriteLockFieldName(String JavaDoc writeLockFieldName) {
641         setWriteLockField(new DatabaseField(writeLockFieldName));
642     }
643
644     /**
645      * PUBLIC:
646      * Configure the version lock value to be stored in the cache.
647      * This allows for the object not to require to store its version value as an attribute.
648      * Note: if using a stateless model where the object can be passed to a client and then
649      * later updated in a different transaction context, then the version lock value should
650      * not be stored in the cache, but in the object to ensure it is the correct value for
651      * that object. This is the default.
652      */

653     public void storeInCache() {
654         lockValueStored = IN_CACHE;
655     }
656
657     /**
658      * PUBLIC:
659      * Configure the version lock value to be stored in the object.
660      * The object must define a mapping and an attribute to store the version value.
661      * Note: the value will be updated internally by TopLink and should not be updated
662      * by the application.
663      */

664     public void storeInObject() {
665         lockValueStored = IN_OBJECT;
666     }
667
668     /**
669      * INTERNAL:
670      * This method updates the modify row, and the domain object
671      * with the new lock value.
672      *
673      * #see this method in VersionLockingPolicy
674      */

675     public void updateRowAndObjectForUpdate(ObjectLevelModifyQuery query, Object JavaDoc domainObject) {
676         Object JavaDoc lockValue = getNewLockValue(query);
677         if (isStoredInCache()) {
678             query.getSession().getIdentityMapAccessor().updateWriteLockValue(query.getPrimaryKey(), domainObject.getClass(), lockValue);
679         }
680         updateWriteLockValueForWrite(query, lockValue);
681     }
682
683     /**
684      * INTERNAL:
685      * This method updates the modify row with the old lock value.
686      */

687     public void writeLockValueIntoRow(ObjectLevelModifyQuery query, Object JavaDoc domainObject) {
688         Object JavaDoc lockValue = getWriteLockValue(domainObject, query.getPrimaryKey(), query.getSession());
689         query.getModifyRow().put(getWriteLockField(), lockValue);
690         if (isStoredInCache()) {
691             query.getSession().getIdentityMapAccessor().updateWriteLockValue(query.getPrimaryKey(), domainObject.getClass(), lockValue);
692         }
693     }
694
695     /**
696      * INTERNAL:
697      * Check the row count for lock failure.
698      */

699     public void validateDelete(int rowCount, Object JavaDoc object, DeleteObjectQuery query) {
700         if (rowCount <= 0) {
701             throw OptimisticLockException.objectChangedSinceLastReadWhenDeleting(object, query);
702         }
703     }
704
705     /**
706      * INTERNAL:
707      * Check the row count for lock failure.
708      */

709     public void validateUpdate(int rowCount, Object JavaDoc object, WriteObjectQuery owner) {
710         if (rowCount <= 0) {
711             throw OptimisticLockException.objectChangedSinceLastReadWhenUpdating(object, owner);
712         }
713     }
714
715     /**
716      * INTERNAL:
717      * Prepare fetch group for read query
718      */

719     public void prepareFetchGroupForReadQuery(FetchGroup fetchGroup, ObjectLevelReadQuery query) {
720         //version stored in object, add the version attribute to the fetch group attribute list
721
if (isStoredInObject()) {
722             String JavaDoc verAttributeName = descriptor.getObjectBuilder().getMappingForField(writeLockField).getAttributeName();
723             fetchGroup.addAttribute(verAttributeName);
724         } else {//stored in cache, add the version field to the select fields
725
if (!query.getAdditionalFields().contains(writeLockField)) {
726                 query.addAdditionalField(writeLockField);
727             }
728         }
729     }
730 }
731
Popular Tags