KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > mappings > foundation > AbstractDirectMapping


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.mappings.foundation;
23
24 import java.util.*;
25 import oracle.toplink.essentials.exceptions.*;
26 import oracle.toplink.essentials.internal.descriptors.*;
27 import oracle.toplink.essentials.internal.helper.*;
28 import oracle.toplink.essentials.internal.sessions.*;
29 import oracle.toplink.essentials.mappings.DatabaseMapping;
30 import oracle.toplink.essentials.mappings.converters.*;
31 import oracle.toplink.essentials.queryframework.*;
32 import oracle.toplink.essentials.sessions.ObjectCopyingPolicy;
33 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
34 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl;
35 import oracle.toplink.essentials.internal.sessions.AbstractSession;
36 import oracle.toplink.essentials.internal.queryframework.JoinedAttributeManager;
37
38 /**
39  * <b>Purpose</b>: Maps an attribute to the corresponding database field type.
40  * The list of field types that are supported by TopLink's direct to field mapping
41  * is dependent on the relational database being used.
42  * A converter can be used to convert between the object and data type if they do not match.
43  *
44  * @see Converter
45  * @see ObjectTypeConverter
46  * @see TypeConversionConverter
47  * @see SerializedObjectConverter
48  *
49  * @author Sati
50  * @since TopLink/Java 1.0
51  */

52 public abstract class AbstractDirectMapping extends DatabaseMapping {
53
54     /** DatabaseField which this mapping represents. */
55     protected DatabaseField field;
56
57     /** To specify the conversion type */
58     protected transient Class JavaDoc attributeClassification;
59     protected transient String JavaDoc attributeClassificationName;
60     
61     /** PERF: Also store object class of attribute in case of primitive. */
62     protected transient Class JavaDoc attributeObjectClassification;
63
64     /** Allows user defined conversion between the object attribute value and the database value. */
65     protected Converter converter;
66
67     /** Support specification of the value to use for null. */
68     protected transient Object JavaDoc nullValue;
69
70     /**
71      * PERF: Indicates if this mapping's attribute is a simple atomic value and cannot be modified, only replaced.
72      * This is a tri-state to allow user to set to true or false, as default is false but
73      * some data-types such as Calendar or byte[] or converter types may be desired to be used as mutable.
74      */

75     protected Boolean JavaDoc isMutable;
76
77     /**
78      * Default constructor.
79      */

80     public AbstractDirectMapping() {
81         super();
82         this.setWeight(WEIGHT_1);
83     }
84
85     /**
86      * PUBLIC:
87      * Return the converter on the mapping.
88      * A converter can be used to convert between the object's value and database value of the attribute.
89      */

90     public Converter getConverter() {
91         return converter;
92     }
93
94     /**
95      * PUBLIC:
96      * Set the converter on the mapping.
97      * A converter can be used to convert between the object's value and database value of the attribute.
98      */

99     public void setConverter(Converter converter) {
100         this.converter = converter;
101     }
102
103     /**
104      * PUBLIC:
105      * Return true if the attribute for this mapping is a simple atomic value that cannot be modified,
106      * only replaced.
107      * This is false by default unless a mutable converter is used such as the SerializedObjectConverter.
108      * This can be set to false in this case, or if a Calendar or byte[] is desired to be used as a mutable value it can be set to true.
109      */

110     public boolean isMutable() {
111         if (isMutable == null) {
112             return false;
113         }
114         return isMutable.booleanValue();
115     }
116
117     /**
118      * PUBLIC:
119      * Return true if the attribute for this mapping is a simple atomic value that cannot be modified,
120      * only replaced.
121      * This is false by default unless a mutable converter is used such as the SerializedObjectConverter.
122      * This can be set to false in this case, or if a Calendar or byte[] is desired to be used as a mutable value it can be set to true.
123      */

124     public void setIsMutable(boolean isMutable) {
125         if (isMutable == true) {
126             this.isMutable = Boolean.TRUE;
127         } else {
128             this.isMutable = Boolean.FALSE;
129         }
130     }
131
132     /**
133      * INTERNAL:
134      * Clone the attribute from the clone and assign it to the backup.
135      */

136     public void buildBackupClone(Object JavaDoc clone, Object JavaDoc backup, UnitOfWorkImpl unitOfWork) {
137         buildClone(clone, backup, unitOfWork, null);
138     }
139
140     /**
141      * INTERNAL:
142      * Clone the attribute from the original and assign it to the clone.
143      */

144     public void buildClone(Object JavaDoc original, Object JavaDoc clone, UnitOfWorkImpl unitOfWork, JoinedAttributeManager joinedAttributeManager) {
145         buildCloneValue(original, clone, unitOfWork);
146     }
147
148     /**
149      * INTERNAL:
150      * Clone the attribute from the original and assign it to the clone.
151      */

152     public void buildCloneValue(Object JavaDoc original, Object JavaDoc clone, AbstractSession session) {
153         // Optimized for clone copy policy, setting of the value is not required.
154
if (isCloningRequired()) {
155             Object JavaDoc attributeValue = getAttributeValueFromObject(original);
156             if (isMutable()) {
157                 attributeValue = getAttributeValue(getFieldValue(attributeValue, session), session);
158             }
159             setAttributeValueInObject(clone, attributeValue);
160         }
161     }
162
163     /**
164      * INTERNAL:
165      * Copy of the attribute of the object.
166      * This is NOT used for unit of work but for templatizing an object.
167      */

168     public void buildCopy(Object JavaDoc copy, Object JavaDoc original, ObjectCopyingPolicy policy) {
169         buildCloneValue(original, copy, policy.getSession());
170     }
171
172     /**
173      * INTERNAL:
174      * Cascade perform delete through mappings that require the cascade
175      */

176     public void cascadePerformRemoveIfRequired(Object JavaDoc object, UnitOfWorkImpl uow, IdentityHashtable visitedObjects) {
177         //objects referenced by this mapping are not registered as they have
178
// no identity, this is a no-op.
179
}
180
181     /**
182      * INTERNAL:
183      * Cascade registerNew for Create through mappings that require the cascade
184      */

185     public void cascadeRegisterNewIfRequired(Object JavaDoc object, UnitOfWorkImpl uow, IdentityHashtable visitedObjects) {
186         //objects referenced by this mapping are not registered as they have
187
// no identity, this is a no-op.
188
}
189
190     /**
191      * INTERNAL:
192      * The mapping clones itself to create deep copy.
193      */

194     public Object JavaDoc clone() {
195         AbstractDirectMapping clone = (AbstractDirectMapping)super.clone();
196
197         // Field must be cloned so aggregates do not share fields.
198
clone.setField((DatabaseField)getField().clone());
199
200         return clone;
201     }
202
203     /**
204      * Returns the field this mapping represents.
205      */

206     protected Vector collectFields() {
207         Vector databaseField = new Vector(1);
208
209         databaseField.addElement(getField());
210         return databaseField;
211     }
212
213     /**
214      * INTERNAL:
215      * Compare the clone and backup clone values and return a change record if the value changed.
216      */

217     public ChangeRecord compareForChange(Object JavaDoc clone, Object JavaDoc backUp, ObjectChangeSet owner, AbstractSession session) {
218         // same code as write from object into row for update
219
if ((owner.isNew()) || (!compareObjects(backUp, clone, session))) {
220             return buildChangeRecord(clone, owner, session);
221         }
222         return null;
223     }
224
225     /**
226      * INTERNAL:
227      * Directly build a change record without comparison
228      */

229     public ChangeRecord buildChangeRecord(Object JavaDoc clone, ObjectChangeSet owner, AbstractSession session) {
230         return internalBuildChangeRecord(getAttributeValueFromObject(clone), owner);
231     }
232
233     /**
234      * INTERNAL:
235      * Build a change record
236      */

237     public ChangeRecord internalBuildChangeRecord(Object JavaDoc newValue, ObjectChangeSet owner) {
238         DirectToFieldChangeRecord changeRecord = new DirectToFieldChangeRecord(owner);
239         changeRecord.setAttribute(getAttributeName());
240         changeRecord.setMapping(this);
241         changeRecord.setNewValue(newValue);
242         return changeRecord;
243     }
244
245     /**
246      * INTERNAL:
247      * Compare the attributes belonging to this mapping for the objects.
248      */

249     public boolean compareObjects(Object JavaDoc firstObject, Object JavaDoc secondObject, AbstractSession session) {
250         Object JavaDoc one = getAttributeValueFromObject(firstObject);
251         Object JavaDoc two = getAttributeValueFromObject(secondObject);
252
253         // PERF: Check identity before conversion.
254
if (one == two) {
255             return true;
256         }
257
258         // CR2114 - following two lines modified; getFieldValue() needs class as an argument
259
one = getFieldValue(one, session);
260         two = getFieldValue(two, session);
261         // PERF: Check identity/nulls before special type comparison.
262
if (one == two) {
263             return true;
264         }
265
266         if ((one == null) || (two == null)) {
267             return false;
268         }
269
270         // Arrays must be checked for equality because default does identity
271
if ((one.getClass() == ClassConstants.APBYTE) && (two.getClass() == ClassConstants.APBYTE)) {
272             return Helper.compareByteArrays((byte[])one, (byte[])two);
273         }
274         if ((one.getClass() == ClassConstants.APCHAR) && (two.getClass() == ClassConstants.APCHAR)) {
275             return Helper.compareCharArrays((char[])one, (char[])two);
276         }
277         if ((one.getClass().isArray()) && (two.getClass().isArray())) {
278             return Helper.compareArrays((Object JavaDoc[])one, (Object JavaDoc[])two);
279         }
280
281         // BigDecimals equals does not consider the precision correctly
282
if (one instanceof java.math.BigDecimal JavaDoc && two instanceof java.math.BigDecimal JavaDoc) {
283             return Helper.compareBigDecimals((java.math.BigDecimal JavaDoc)one, (java.math.BigDecimal JavaDoc)two);
284         }
285
286         return one.equals(two);
287     }
288     
289     /**
290      * INTERNAL:
291      * Convert all the class-name-based settings in this mapping to actual class-based
292      * settings
293      * This method is implemented by subclasses as necessary.
294      * @param classLoader
295      */

296     public void convertClassNamesToClasses(ClassLoader JavaDoc classLoader){
297         super.convertClassNamesToClasses(classLoader);
298         if (converter != null) {
299             if (converter instanceof TypeConversionConverter) {
300                 ((TypeConversionConverter)converter).convertClassNamesToClasses(classLoader);
301             } else if (converter instanceof ObjectTypeConverter) {
302                 // To avoid 1.5 dependencies with the EnumTypeConverter check
303
// against ObjectTypeConverter.
304
((ObjectTypeConverter) converter).convertClassNamesToClasses(classLoader);
305             }
306         }
307     };
308
309     /**
310      * PUBLIC:
311      * Some databases do not properly support all of the base data types. For these databases,
312      * the base data type must be explicitly specified in the mapping to tell TopLink to force
313      * the instance variable value to that data type
314      */

315     public Class JavaDoc getAttributeClassification() {
316         return attributeClassification;
317     }
318
319     public String JavaDoc getAttributeClassificationName() {
320         return attributeClassificationName;
321     }
322
323     /**
324      * INTERNAL:
325      * Allows for subclasses to convert the attribute value.
326      */

327     public Object JavaDoc getAttributeValue(Object JavaDoc fieldValue, AbstractSession session) {
328         // PERF: Direct variable access.
329
Object JavaDoc attributeValue = fieldValue;
330         if ((fieldValue == null) && (getNullValue() != null)) {// Translate default null value
331
return this.nullValue;
332         }
333
334         // Allow for user defined conversion to the object value.
335
if (this.converter != null) {
336             attributeValue = this.converter.convertDataValueToObjectValue(attributeValue, session);
337         } else {
338             // PERF: Avoid conversion check when not required.
339
if ((attributeValue == null) || (attributeValue.getClass() != this.attributeObjectClassification)) {
340                 try {
341                     attributeValue = session.getDatasourcePlatform().convertObject(attributeValue, this.attributeClassification);
342                 } catch (ConversionException e) {
343                     throw ConversionException.couldNotBeConverted(this, getDescriptor(), e);
344                 }
345             }
346         }
347         if (attributeValue == null) {// Translate default null value, conversion may have produced null.
348
attributeValue = this.nullValue;
349         }
350
351         return attributeValue;
352     }
353
354     /**
355      * INTERNAL:
356      * Returns the field which this mapping represents.
357      */

358     public DatabaseField getField() {
359         return field;
360     }
361
362     /**
363      * INTERNAL:
364      */

365     public boolean isAbstractDirectMapping() {
366         return true;
367     }
368
369     /**
370      * INTERNAL:
371      * Return the classifiction for the field contained in the mapping.
372      * This is used to convert the row value to a consistent Java value.
373      */

374     public Class JavaDoc getFieldClassification(DatabaseField fieldToClassify) {
375         // PERF: This method is a major performance code point,
376
// so has been micro optimized and uses direct variable access.
377
if (fieldToClassify.type != null) {
378             return fieldToClassify.type;
379         } else {
380             if (this.converter != null) {
381                 return null;
382             } else {
383                 return this.attributeClassification;
384             }
385         }
386     }
387
388     /**
389      * ADVANCED:
390      * Return the class type of the field value.
391      * This can be used if field value differs from the object value,
392      * has specific typing requirements such as usage of java.sql.Blob or NChar.
393      */

394     public Class JavaDoc getFieldClassification() {
395         if (getField() == null) {
396             return null;
397         }
398         return getField().getType();
399     }
400
401     /**
402      * ADVANCED:
403      * Set the class type of the field value.
404      * This can be used if field value differs from the object value,
405      * has specific typing requirements such as usage of java.sql.Blob or NChar.
406      * This must be called after the field name has been set.
407      */

408     public void setFieldClassification(Class JavaDoc fieldType) {
409         getField().setType(fieldType);
410     }
411
412     /**
413      * ADVANCED:
414      * Set the JDBC type of the field value.
415      * This can be used if field type does not corespond directly to a Java class type,
416      * such as MONEY.
417      * This is used for binding.
418      */

419     public void setFieldType(int jdbcType) {
420         getField().setSqlType(jdbcType);
421     }
422
423     /**
424      * PUBLIC:
425      * Name of the field this mapping represents.
426      */

427     public String JavaDoc getFieldName() {
428         return getField().getQualifiedName();
429     }
430
431     /**
432      * INTERNAL:
433      * Convert the attribute value to a field value.
434      * Process any converter if defined, and check for null values.
435      */

436     public Object JavaDoc getFieldValue(Object JavaDoc attributeValue, AbstractSession session) {
437         // PERF: This method is a major performance code point,
438
// so has been micro optimized and uses direct variable access.
439
Object JavaDoc fieldValue = attributeValue;
440         if ((this.nullValue != null) && (this.nullValue.equals(fieldValue))) {
441             return null;
442         }
443
444         // Allow for user defined conversion to the object value.
445
if (this.converter != null) {
446             fieldValue = this.converter.convertObjectValueToDataValue(fieldValue, session);
447         }
448         Class JavaDoc fieldClassification = getFieldClassification(getField());
449         // PERF: Avoid conversion if not required.
450
if ((fieldValue == null) || (fieldClassification != fieldValue.getClass())) {
451             try {
452                 fieldValue = session.getPlatform(getDescriptor().getJavaClass()).convertObject(fieldValue, fieldClassification);
453             } catch (ConversionException exception) {
454                 throw ConversionException.couldNotBeConverted(this, getDescriptor(), exception);
455             }
456         }
457         return fieldValue;
458     }
459
460     /**
461      * PUBLIC:
462      * Allow for the value used for null to be specified.
463      * This can be used to convert database null values to application specific values, when null values
464      * are not allowed by the application (such as in primitives).
465      * Note: the default value for NULL is used on reads, writes, and query SQL generation
466      */

467     public Object JavaDoc getNullValue() {
468         return nullValue;
469     }
470
471     /**
472      * INTERNAL:
473      * Return the weight of the mapping, used to sort mappings to ensure that
474      * DirectToField Mappings get merged first
475      */

476     public Integer JavaDoc getWeight() {
477         return this.weight;
478     }
479     
480     /**
481      * INTERNAL:
482      * Initialize the attribute classification.
483      */

484     public void preInitialize(AbstractSession session) throws DescriptorException {
485         super.preInitialize(session);
486         this.attributeClassification = getAttributeAccessor().getAttributeClass();
487         this.attributeObjectClassification = Helper.getObjectClass(this.attributeClassification);
488     }
489     
490     /**
491      * INTERNAL:
492      * The mapping is initialized with the given session.
493      * This mapping is fully initialized after this.
494      */

495     public void initialize(AbstractSession session) throws DescriptorException {
496         super.initialize(session);
497
498         // Initialize isMutable if not specified, default is false (assumes atomic).
499
if (this.isMutable == null) {
500             if (getConverter() != null) {
501                 setIsMutable(getConverter().isMutable());
502             } else {
503                 setIsMutable(false);
504             }
505         }
506
507         if (getField() == null) {
508             session.getIntegrityChecker().handleError(DescriptorException.fieldNameNotSetInMapping(this));
509         }
510
511         getDescriptor().buildField(getField());
512         setFields(collectFields());
513
514         if (getConverter() != null) {
515             getConverter().initialize(this, session);
516         }
517     }
518
519     /**
520      * INTERNAL:
521      */

522     public boolean isDirectToFieldMapping() {
523         return true;
524     }
525
526     /**
527      * INTERNAL:
528      * Iterate on the appropriate attribute.
529      */

530     public void iterate(DescriptorIterator iterator) {
531         // PERF: Only iterate when required.
532
if (iterator.shouldIterateOnPrimitives()) {
533             iterator.iteratePrimitiveForMapping(getAttributeValueFromObject(iterator.getVisitedParent()), this);
534         }
535     }
536
537     /**
538      * INTERNAL:
539      * Merge changes from the source to the target object.
540      */

541     public void mergeChangesIntoObject(Object JavaDoc target, ChangeRecord changeRecord, Object JavaDoc source, MergeManager mergeManager) {
542         setAttributeValueInObject(target, ((DirectToFieldChangeRecord)changeRecord).getNewValue());
543     }
544
545     /**
546      * INTERNAL:
547      * Merge changes from the source to the target object. This merge is only called when a changeSet for the target
548      * does not exist or the target is uninitialized
549      */

550     public void mergeIntoObject(Object JavaDoc target, boolean isTargetUnInitialized, Object JavaDoc source, MergeManager mergeManager) {
551         Object JavaDoc attributeValue = getAttributeValueFromObject(source);
552         if ( (this.getDescriptor().getObjectChangePolicy().isObjectChangeTrackingPolicy()) && (!compareObjects(target, source, mergeManager.getSession())) ) {
553             // if it didn't change then there will be no event
554
Object JavaDoc targetAttribute = getAttributeValueFromObject(target);
555             setAttributeValueInObject(target, attributeValue);
556             //set the value first, if the owner is new ( or aggregate) the change set may be created directly
557
//from the target.
558
this.getDescriptor().getObjectChangePolicy().raiseInternalPropertyChangeEvent(target, getAttributeName(), targetAttribute, attributeValue);
559         }else{
560             //just set the value and continue
561
setAttributeValueInObject(target, attributeValue);
562         }
563     }
564
565     /**
566      * PUBLIC:
567      * Some databases do not properly support all of the base data types. For these databases,
568      * the base data type must be explicitly specified in the mapping to tell TopLink to force
569      * the instance variable value to that data type
570      */

571     public void setAttributeClassification(Class JavaDoc attributeClassification) {
572         this.attributeClassification = attributeClassification;
573     }
574
575     /**
576      * INTERNAL:
577      * Set the name of the class for MW usage.
578      */

579     public void setAttributeClassificationName(String JavaDoc attributeClassificationName) {
580         this.attributeClassificationName = attributeClassificationName;
581     }
582
583     /**
584      * ADVANCED:
585      * Set the field in the mapping.
586      * This can be used for advanced field types, such as XML nodes, or to set the field type.
587      */

588     public void setField(DatabaseField theField) {
589         field = theField;
590     }
591
592     /**
593      * PUBLIC:
594      * Allow for the value used for null to be specified.
595      * This can be used to convert database null values to application specific values, when null values
596      * are not allowed by the application (such as in primitives).
597      * Note: the default value for NULL is used on reads, writes, and query SQL generation
598      */

599     public void setNullValue(Object JavaDoc nullValue) {
600         this.nullValue = nullValue;
601     }
602
603     /**
604      * INTERNAL:
605      */

606     public String JavaDoc toString() {
607         return getClass().getName() + "[" + getAttributeName() + "-->" + getField() + "]";
608     }
609
610     /**
611      * INTERNAL:
612      * Either create a new change record or update with the new value. This is used
613      * by attribute change tracking.
614      */

615     public void updateChangeRecord(Object JavaDoc clone, Object JavaDoc newValue, Object JavaDoc oldValue, ObjectChangeSet objectChangeSet, UnitOfWorkImpl uow) {
616         DirectToFieldChangeRecord changeRecord = (DirectToFieldChangeRecord)objectChangeSet.getChangesForAttributeNamed(this.getAttributeName());
617         if (changeRecord == null) {
618             objectChangeSet.addChange(internalBuildChangeRecord(newValue, objectChangeSet));
619         } else {
620             changeRecord.setNewValue(newValue);
621         }
622     }
623
624     /**
625      * INTERNAL:
626      * Return if this mapping supports change tracking.
627      */

628     public boolean isChangeTrackingSupported() {
629         return !isMutable();
630     }
631     
632     /**
633      * INTERNAL:
634      * Return if this mapping requires its attribute value to be cloned.
635      */

636     public boolean isCloningRequired() {
637         return isMutable() || getDescriptor().getCopyPolicy().buildsNewInstance();
638     }
639
640     /**
641      * INTERNAL:
642      * Allow for subclasses to perform validation.
643      */

644     public void validateBeforeInitialization(AbstractSession session) throws DescriptorException {
645         if ((getFieldName() == null) || (getFieldName().length() == 0)) {
646             session.getIntegrityChecker().handleError(DescriptorException.noFieldNameForMapping(this));
647         }
648     }
649
650     /**
651      * INTERNAL:
652      * Get the value from the object for this mapping.
653      */

654     public Object JavaDoc valueFromObject(Object JavaDoc object, DatabaseField field, AbstractSession session) throws DescriptorException {
655         return getFieldValue(getAttributeValueFromObject(object), session);
656     }
657
658     /**
659      * INTERNAL:
660      * Extract value from the row and set the attribute to this value in the
661      * working copy clone.
662      * In order to bypass the shared cache when in transaction a UnitOfWork must
663      * be able to populate working copies directly from the row.
664      */

665     public void buildCloneFromRow(AbstractRecord databaseRow, JoinedAttributeManager joinManager, Object JavaDoc clone, ObjectBuildingQuery sourceQuery, UnitOfWorkImpl unitOfWork, AbstractSession executionSession) {
666         // Even though the correct value may exist on the original, we can't
667
// make that assumption. It is easy to just build it again from the
668
// row even if copy policy already copied it.
669
// That optimization is lost.
670
Object JavaDoc attributeValue = valueFromRow(databaseRow, joinManager, sourceQuery, executionSession);
671
672         setAttributeValueInObject(clone, attributeValue);
673     }
674
675     /**
676      * INTERNAL:
677      * Builds a shallow original object. Only direct attributes and primary
678      * keys are populated. In this way the minimum original required for
679      * instantiating a working copy clone can be built without placing it in
680      * the shared cache (no concern over cycles).
681      * @parameter original later the input to buildCloneFromRow
682      */

683     public void buildShallowOriginalFromRow(AbstractRecord databaseRow, Object JavaDoc original, ObjectBuildingQuery query, AbstractSession executionSession) {
684         readFromRowIntoObject(databaseRow, null, original, query, executionSession);
685     }
686
687     /**
688      * INTERNAL:
689      * In the case of building a UnitOfWork clone directly from a row, the
690      * session set in the query will not know which database platform to use
691      * for converting the value. Allows the correct session to be passed in.
692      * @param row
693      * @param query
694      * @param executionSession
695      * @return
696      */

697     public Object JavaDoc valueFromRow(AbstractRecord row, JoinedAttributeManager joinManager, ObjectBuildingQuery query, AbstractSession executionSession) {
698         // PERF: Direct variable access.
699
Object JavaDoc fieldValue = row.get(this.field);
700         Object JavaDoc attributeValue = getAttributeValue(fieldValue, executionSession);
701
702         return attributeValue;
703     }
704
705     /**
706      * INTERNAL:
707      * Get a value from the object and set that in the respective field of the row.
708      */

709     public void writeFromObjectIntoRow(Object JavaDoc object, AbstractRecord row, AbstractSession session) {
710         if (isReadOnly()) {
711             return;
712         }
713
714         Object JavaDoc attributeValue = getAttributeValueFromObject(object);
715         Object JavaDoc fieldValue = getFieldValue(attributeValue, session);
716
717         writeValueIntoRow(row, getField(), fieldValue);
718
719     }
720
721     protected abstract void writeValueIntoRow(AbstractRecord row, DatabaseField field, Object JavaDoc value);
722
723     /**
724      * INTERNAL:
725      * Get a value from the object and set that in the respective field of the row.
726      */

727     public void writeFromObjectIntoRowWithChangeRecord(ChangeRecord changeRecord, AbstractRecord row, AbstractSession session) {
728         if (isReadOnly()) {
729             return;
730         }
731
732         Object JavaDoc attributeValue = ((DirectToFieldChangeRecord)changeRecord).getNewValue();
733         Object JavaDoc fieldValue = getFieldValue(attributeValue, session);
734
735         row.add(getField(), fieldValue);
736     }
737
738     /**
739      * INTERNAL:
740      * Write the attribute value from the object to the row for update.
741      */

742     public void writeFromObjectIntoRowForUpdate(WriteObjectQuery query, AbstractRecord aDatabaseRow) {
743         if (query.getSession().isUnitOfWork()) {
744             if (compareObjects(query.getBackupClone(), query.getObject(), query.getSession())) {
745                 return;
746             }
747         }
748
749         super.writeFromObjectIntoRowForUpdate(query, aDatabaseRow);
750     }
751
752     /**
753      * INTERNAL:
754      * Write fields needed for insert into the template for with null values.
755      */

756     public void writeInsertFieldsIntoRow(AbstractRecord databaseRow, AbstractSession session) {
757         if (isReadOnly()) {
758             return;
759         }
760
761         databaseRow.add(getField(), null);
762     }
763 }
764
Popular Tags