KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jdo > spi > persistence > support > sqlstore > model > ForeignFieldDesc


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 in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
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 Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * ForeignFieldDesc.java
26  *
27  * Created on March 3, 2000
28  *
29  */

30
31 package com.sun.jdo.spi.persistence.support.sqlstore.model;
32
33 import org.netbeans.modules.dbschema.ColumnElement;
34 import org.netbeans.modules.dbschema.TableElement;
35 import com.sun.jdo.api.persistence.model.jdo.RelationshipElement;
36 import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
37 import com.sun.jdo.spi.persistence.support.sqlstore.SQLStateManager;
38 import com.sun.jdo.spi.persistence.utility.I18NHelper;
39 import com.sun.jdo.spi.persistence.utility.logging.Logger;
40
41 import java.lang.reflect.Field JavaDoc;
42 import java.util.ArrayList JavaDoc;
43
44 /**
45  *
46  */

47 public class ForeignFieldDesc extends FieldDesc {
48
49     // Values for deleteAction
50
/**
51      * When the parent object is deleted from db,
52      * delete the relationship object described by this object also.
53      */

54     public static final int ACT_CASCADE = RelationshipElement.CASCADE_ACTION;
55
56     /**
57      * When the parent object is deleted,
58      * no action is required for the relationship object described by this object.
59      */

60     public static final int ACT_NONE = RelationshipElement.NONE_ACTION;
61
62     /** Currently runtime code does not interprete this action. */
63     public static final int ACT_NULLIFY = RelationshipElement.NULLIFY_ACTION;
64
65     /** Currently runtime code does not interprete this action. */
66     public static final int ACT_RESTRICT = RelationshipElement.RESTRICT_ACTION;
67
68     /** Currently runtime code does not interprete this action. */
69     public static final int ACT_AGGREGATE = RelationshipElement.AGGREGATE_ACTION;
70
71     /** Class descriptor for the class of this relationship field. */
72     public ClassDesc foreignConfig;
73
74     public int cardinalityLWB;
75
76     public int cardinalityUPB;
77
78     // Takes one of the following values.
79
public int deleteAction;
80
81     /** Array of LocalFieldDesc. */
82     public ArrayList JavaDoc foreignFields;
83
84     /** Array of ColumnElement. */
85     public ArrayList JavaDoc foreignColumns;
86
87     /** Array of LocalFieldDesc. */
88     public ArrayList JavaDoc localFields;
89
90     /** Array of ColumnElement. */
91     public ArrayList JavaDoc localColumns;
92
93     /** Array of LocalFieldDesc. */
94     public ArrayList JavaDoc assocForeignFields;
95
96     /** Array of ColumnElement. */
97     public ArrayList JavaDoc assocForeignColumns;
98
99     /** Array of LocalFieldDesc. */
100     public ArrayList JavaDoc assocLocalFields;
101
102     /** Array of ColumnElement. */
103     public ArrayList JavaDoc assocLocalColumns;
104
105     /**
106      * If inverseRelationshipField is not null, it means this field is
107      * under managed relationship. Otherwise, this is a one-way relationship.
108      */

109     private ForeignFieldDesc inverseRelationshipField;
110
111     /**
112      * True, if the relationship is mapped to primary key fields
113      * <b>on the other relationship side</b>.
114      */

115     private boolean isMappedToPk;
116
117     ForeignFieldDesc(ClassDesc config) {
118         super(config);
119     }
120
121     /**
122      * Returns true.
123      */

124     public boolean isRelationshipField() {
125         return true;
126     }
127
128     /**
129      * Returns true, if the relationship is mapped to a join table.
130      *
131      * @return True, if the relationship is mapped to a join table, false otherwise.
132      */

133     public boolean useJoinTable() {
134         return (assocLocalColumns != null && assocLocalColumns.size() > 0);
135     }
136
137     /**
138      * Checks the conditions that guarantee, that we have the foreign
139      * key on this side.
140      *
141      * @return True, if this relationship is mapped to foreign keys and the
142      * foreign key is on the local side. False otherwise.
143      */

144     public boolean hasForeignKey() {
145         boolean result = false;
146
147         // RESOLVE: Can't check PROP_REF_INTEGRITY_UPDATES for 1 way mappings.
148
// See #checkReferentialIntegrityUpdatesForObjectField.
149
if (inverseRelationshipField != null) {
150             result = cardinalityUPB == 1 && !useJoinTable() &&
151                     (sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) > 0;
152         }
153         return result;
154     }
155
156     /**
157      * Returns true, if the relationship is mapped to primary key fields
158      * <b>on the other relationship side</b>.
159      *
160      * @return True, if the relationship is mapped to primary key fields
161      * <b>on the other relationship side</b>, false otherwise.
162      * @see #initializeIsMappedToPk
163      */

164     public boolean isMappedToPk() {
165         return isMappedToPk;
166     }
167
168     public ArrayList JavaDoc getLocalFields() {
169         if (localFields == null) {
170             localFields = new ArrayList JavaDoc();
171         }
172
173         return localFields;
174     }
175
176     public ArrayList JavaDoc getForeignFields() {
177         if (foreignFields == null) {
178             foreignFields = new ArrayList JavaDoc();
179         }
180
181         return foreignFields;
182     }
183
184     public ArrayList JavaDoc getAssocLocalFields() {
185         // Only create assocLocalFields if there is a corresponding
186
// assocLocalColumns to save space.
187
if (assocLocalFields == null && assocLocalColumns != null) {
188             assocLocalFields = new ArrayList JavaDoc();
189         }
190
191         return assocLocalFields;
192     }
193
194     public ArrayList JavaDoc getAssocForeignFields() {
195         // Only create assocForeignFields if there is a corresponding
196
// assocForeignColumns to save space.
197
if (assocForeignFields == null && assocForeignColumns != null) {
198             assocForeignFields = new ArrayList JavaDoc();
199         }
200
201         return assocForeignFields;
202     }
203
204     public ForeignFieldDesc getInverseRelationshipField() {
205         return inverseRelationshipField;
206     }
207
208     /**
209      * Constructs the oid of a related instance. If called by {@link
210      * SQLStateManager#updateTrackedFields}, the new value for the
211      * local field <code>fieldDesc</code> is not yet set and passed as
212      * parameter <code>value</code>. If called for navigation by
213      * {@link SQLStateManager#populateForeignField}, values of updated
214      * local fields must be retrieved from the before image. In both
215      * cases, the actual call to this method is in {@link
216      * SQLStateManager#getObjectById}.<p>
217      * For tracked field usage, see
218      * {@link SQLStateManager#setForeignKey} and
219      * {@link SQLStateManager#updateTrackedFields}.
220      * For navigation usage, see
221      * {@link SQLStateManager#realizeForeignField}.
222      *
223      * @param sm State manager on the local side.
224      * @param fieldDesc Local field being set.
225      * @param value New value of the field being set.
226      * @return The object id for the related instance. This id is used
227      * to lookup the instance from the persistence manager cache. The
228      * construced oid is invalid, if one of the oid fields is
229      * null. In this case the returned value is null.
230      */

231     public Object JavaDoc createObjectId(SQLStateManager sm, LocalFieldDesc fieldDesc, Object JavaDoc value) {
232
233         assert isMappedToPk();
234
235         Class JavaDoc oidClass = foreignConfig.getOidClass();
236         Object JavaDoc oid = null;
237
238         try {
239             oid = oidClass.newInstance();
240         } catch (Exception JavaDoc e) {
241             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
242                     "core.statemanager.cantnewoid", oidClass.getName()), e); // NOI18N
243
}
244
245         Field JavaDoc keyFields[] = foreignConfig.getKeyFields();
246         String JavaDoc keyFieldNames[] = foreignConfig.getKeyFieldNames();
247         for (int i = 0; i < keyFields.length && oid != null; i++) {
248             Field JavaDoc keyField = keyFields[i];
249
250             for (int j = 0; j < foreignFields.size() && oid != null; j++) {
251                 LocalFieldDesc fa = (LocalFieldDesc) foreignFields.get(j);
252
253                 if (fa.getName().compareTo(keyFieldNames[i]) == 0) {
254                     LocalFieldDesc la = (LocalFieldDesc) localFields.get(j);
255                     Object JavaDoc keyFieldValue = null;
256
257                     if (la == fieldDesc) {
258                         keyFieldValue = value;
259                     } else if (sm.getSetMaskBit(la.absoluteID) && !sm.getSetMaskBit(absoluteID)) {
260                         keyFieldValue = la.getValue(sm.getBeforeImage());
261                     } else {
262                         keyFieldValue = la.getValue(sm);
263                     }
264
265                     if (keyFieldValue != null) {
266                         try {
267                             // We need to convert the keyFieldValue to the proper type before
268
// setting it.
269
keyField.set(oid, fa.convertValue(keyFieldValue, sm));
270                         } catch (IllegalAccessException JavaDoc e) {
271                             throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
272                                     "core.statemanager.cantsetkeyfield", keyField.getName()), e); // NOI18N
273
}
274                     } else {
275                         oid = null;
276                     }
277                 }
278             }
279         }
280
281         return oid;
282     }
283
284     //
285
// ------------ Initialisation methods ------------
286
//
287

288     // TODO: Should be removed, once computeTrackeRelationshipFields is removed.
289
private void setInverseRelationshipField(ForeignFieldDesc f) {
290         inverseRelationshipField = f;
291     }
292
293     void computeTrackedRelationshipFields() {
294         // If the field is a ForeignFieldDesc, we only need
295
// to compare against other ForeignFieldDesc. The reason
296
// is that ForeignFieldDesc implicitly tracks a LocalFieldDesc
297
// (foreign key field) via relationship updates.
298

299         ForeignFieldDesc inverseField = getInverseRelationshipField();
300
301         for (int k = 0; k < classDesc.foreignFields.size(); k++) {
302             ForeignFieldDesc tf = (ForeignFieldDesc) classDesc.foreignFields.get(k);
303
304             if ((this != tf) && (getType() == tf.getType()) && (compareColumns(this, tf) == true)) {
305                 if ((inverseField != null) &&
306                         (tf.getInverseRelationshipField() == null)) {
307                     tf.setInverseRelationshipField(inverseField);
308                 }
309
310                 // Mark the relationship field tracking the foreign key as primary.
311
if ((sqlProperties & FieldDesc.PROP_SECONDARY_TRACKED_FIELD) == 0) {
312                     sqlProperties |= FieldDesc.PROP_PRIMARY_TRACKED_FIELD;
313                 }
314
315                 if ((tf.sqlProperties & FieldDesc.PROP_PRIMARY_TRACKED_FIELD) == 0) {
316                     tf.sqlProperties |= FieldDesc.PROP_SECONDARY_TRACKED_FIELD;
317                 }
318
319                 addTrackedField(tf);
320             }
321         }
322     }
323
324     /**
325      * Initializes relationship field information.
326      *
327      * @param foreignConfig Class descriptor of the foreign class.
328      * @param inverseField The inverse relationship field.
329      */

330     void fixupForeignReference(ClassDesc foreignConfig,
331                                ForeignFieldDesc inverseField) {
332
333         registerForeignConfig(foreignConfig, inverseField);
334         initializeFieldLists();
335         initializeIsMappedToPk();
336         addForeignKeyFieldsToDFG();
337     }
338
339     /**
340      * Registers the relationship information about the foreign class.
341      *
342      * @param foreignConfig Class descriptor of the foreign class.
343      * @param inverseField The inverse relationship field.
344      */

345     private void registerForeignConfig(ClassDesc foreignConfig,
346                                        ForeignFieldDesc inverseField) {
347         boolean debug = logger.isLoggable(Logger.FINEST);
348
349         if (debug) {
350             Object JavaDoc[] items = new Object JavaDoc[] {classDesc, this, foreignConfig};
351             logger.finest("sqlstore.model.classdesc.general", items); // NOI18N
352
}
353
354         // Remember the class descriptor for the foreign class.
355
this.foreignConfig = foreignConfig;
356
357         if (debug && inverseField != null) {
358             logger.finest("sqlstore.model.classdesc.assocrelatedfield", inverseField); //NOI18N
359
}
360
361         setInverseRelationshipField(inverseField);
362     }
363
364     /**
365      * Initialize the field lists based on column list information.
366      */

367     private void initializeFieldLists() {
368         ClassDesc theConfig = classDesc;
369
370         for (int i = 0; i < 4; i++) {
371             ArrayList JavaDoc fields = null;
372             ArrayList JavaDoc columns = null;
373
374             switch (i) {
375                 case 0:
376                     columns = localColumns;
377                     fields = getLocalFields();
378                     break;
379                 case 1:
380                     columns = assocLocalColumns;
381                     fields = getAssocLocalFields();
382                     break;
383                 case 2:
384                     columns = assocForeignColumns;
385                     fields = getAssocForeignFields();
386                     break;
387                 case 3:
388                     columns = foreignColumns;
389                     fields = getForeignFields();
390                     theConfig = foreignConfig;
391                     break;
392             }
393
394             if (columns == null) continue;
395
396             for (int j = 0; j < columns.size(); j++) {
397                 ColumnElement ce = (ColumnElement) columns.get(j);
398                 TableElement te = ce.getDeclaringTable();
399
400                 if (te == null) {
401                     throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
402                             "core.configuration.columnnotable")); // NOI18N
403
}
404
405                 fields.add(theConfig.getLocalFieldDesc(ce));
406             }
407         }
408     }
409
410     /**
411      * Checks, if the relationship is mapped to primary key fields
412      * <b>on the other relationship side</b> and sets the property
413      * <code>isMappedToPk</code>.
414      */

415     private void initializeIsMappedToPk() {
416         int count = foreignFields.size();
417
418         isMappedToPk = !useJoinTable() &&
419                 foreignConfig.getKeyFields().length == count;
420
421         for (int i = 0; i < count && isMappedToPk; i++) {
422             isMappedToPk = ((LocalFieldDesc) foreignFields.get(i)).isKeyField();
423         }
424     }
425
426     /**
427      * Silently adding local foreign key fields to the DFG.
428      */

429     private void addForeignKeyFieldsToDFG() {
430         for (int i = 0; i < localFields.size(); i++) {
431             LocalFieldDesc lf = (LocalFieldDesc) localFields.get(i);
432
433             if (lf.absoluteID < 0 && !useJoinTable()) {
434                 classDesc.getFetchGroup(GROUP_DEFAULT).add(lf);
435             }
436         }
437     }
438
439     /**
440      * Determines the relationship side to be updated. Foreign key relationships
441      * must always be updated on the side having the foreign key. Jointable
442      * relationships can be handled from either side. To have unified
443      * dependency management for foreign key _and_ jointable relationships,
444      * it's essential that we apply the same rules defining the updated side
445      * for foreign key and jointable relationships. We also need to always
446      * update the same relationship side.
447      */

448     void fixupFieldProperties() {
449         boolean refIntegrityUpdate = true;
450
451         if (cardinalityUPB > 1) {
452             if (!(refIntegrityUpdate = checkReferentialIntegrityUpdatesForCollectionField())) {
453                 unsetReferentialIntegrityUpdateProperty();
454
455                 // We also unset the IN_CONCURRENCY_CHECK property because we can't
456
// detect concurrency violation for changes made to a Collection
457
sqlProperties &= ~(FieldDesc.PROP_IN_CONCURRENCY_CHECK);
458             }
459         } else {
460
461             if (!(refIntegrityUpdate = checkReferentialIntegrityUpdatesForObjectField())) {
462                 unsetReferentialIntegrityUpdateProperty();
463
464                 sqlProperties &= ~(FieldDesc.PROP_IN_CONCURRENCY_CHECK);
465             }
466         }
467
468         if (!refIntegrityUpdate) {
469             unsetConcurrencyCheckProperty();
470         }
471     }
472
473     /**
474      * Checks, if datastore updates will be scheduled locally or on
475      * the opposite relationship side.
476      *
477      * @return True, if datastore updates for this relationship will
478      * be scheduled locally, false otherwise.
479      */

480     private boolean checkReferentialIntegrityUpdatesForCollectionField() {
481         boolean refIntegrityUpdate;
482         ForeignFieldDesc inverseFieldDesc = getInverseRelationshipField();
483
484         if (inverseFieldDesc == null) {
485             refIntegrityUpdate = defineUpdatedSideXToM();
486         } else {
487             if (inverseFieldDesc.cardinalityUPB <= 1) {
488                 // For 1:N relationships, we always update the relationship side
489
// which includes jointables. We indicate this by unsetting the
490
// REF_INTEGRITY_UPDATES property which means that integrity updates
491
// cannot be done locally.
492
refIntegrityUpdate = false;
493             } else {
494                 // For N:M relationships, we choose the updated relationship side
495
// depending on the alphabethical order of the related class names.
496
// N:M relationships must be mapped to a jointable. As jointable
497
// entries can be created from each side, we just define the side.
498
refIntegrityUpdate = defineUpdatedSideNToM(inverseFieldDesc);
499             }
500         }
501         return refIntegrityUpdate;
502     }
503
504     /**
505      * Checks, if datastore updates will be scheduled locally or on
506      * the opposite relationship side.
507      *
508      * @return True, if datastore updates for this relationship will
509      * be scheduled locally, false otherwise.
510      */

511     private boolean checkReferentialIntegrityUpdatesForObjectField() {
512         boolean refIntegrityUpdate;
513         ForeignFieldDesc inverseFieldDesc = getInverseRelationshipField();
514
515         if (inverseFieldDesc == null) {
516             // Update the local side for one-way relationships.
517
refIntegrityUpdate = true;
518         } else {
519             if (inverseFieldDesc.cardinalityUPB > 1) {
520                 // For 1:N relationships, we always update the local side
521
// which includes jointables. We indicate this by setting the
522
// REF_INTEGRITY_UPDATES property which means that integrity updates
523
// are done locally.
524
refIntegrityUpdate = true;
525             } else {
526                 // For 1:1 relationships, we choose the updated relationship side
527
// depending on the side having the foreign key. If the relationship
528
// is mapped to primary key fields only, we consider if one side
529
// is marked for cascade delete. Otherwise, we choose the updatable
530
// side depending on the alphabethical order of the related class names.
531
refIntegrityUpdate = defineUpdatedSide1To1(inverseFieldDesc);
532             }
533         }
534         return refIntegrityUpdate;
535     }
536
537     /**
538      * Defines the updated side for a collection relationship
539      * mapped one-way.
540      *
541      * @return True, if datastore updates for this relationship will
542      * be scheduled locally, false otherwise.
543      */

544     private boolean defineUpdatedSideXToM() {
545         boolean refIntegrityUpdate;
546         if (!useJoinTable()) {
547             // As this is a foreign key relationship, the other side must
548
// be the one side. Foreign key relationships can be updated
549
// from either side, even if the inverse side is unknown.
550
refIntegrityUpdate = false;
551         } else {
552             // Update the local side for one-way relationships mapped to jointables.
553
refIntegrityUpdate = true;
554         }
555         return refIntegrityUpdate;
556     }
557
558     /**
559      * Defines the updated side for many-to-many relationships. As jointable
560      * entries can be created from either side, we just define the side. The updated
561      * side is chosen based on the alphabethical order of the related class names.
562      *
563      * @param inverseFieldDesc Inverse relationship field.
564      * Is guaranteed to be not null!
565      * @return True, if datastore updates for this relationship will
566      * be scheduled locally, false otherwise.
567      */

568     private boolean defineUpdatedSideNToM(ForeignFieldDesc inverseFieldDesc) {
569         boolean refIntegrityUpdate;
570         final boolean updateOtherSide = (inverseFieldDesc.sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) > 0;
571
572         if (!updateOtherSide) {
573             // The opposite side has already been identified not to be updated.
574
refIntegrityUpdate = true;
575         } else {
576             refIntegrityUpdate = chooseUpdatedSide(inverseFieldDesc);
577         }
578         return refIntegrityUpdate;
579     }
580
581     /**
582      * Defines the updated side for one-to-one relationships. The updated side
583      * is either defined by:
584      *
585      * <ol>
586      * <li>The relationship side mapped to non-key columns.</li>
587      * <li>The relationship side is identified as dependent side, or</li>
588      * <li><ul>
589      * <li>Mark both sides updatable for foreign key relationships.</li>
590      * <li>Choose a side for jointable relationships.</li>
591      * </ul></li>
592      * </ol>
593      *
594      * @param inverseFieldDesc Inverse relationship field.
595      * Is guaranteed to be not null!
596      * @return True, if datastore updates for this relationship will
597      * be scheduled locally, false otherwise.
598      */

599     private boolean defineUpdatedSide1To1(ForeignFieldDesc inverseFieldDesc) {
600         boolean refIntegrityUpdate;
601         final boolean updateOtherSide = (inverseFieldDesc.sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) > 0;
602
603         if (!updateOtherSide) {
604             // The opposite side has already been identified not to be updated.
605
refIntegrityUpdate = true;
606         } else if (!useJoinTable()) {
607             // Check foreign key constraints and the dependent side.
608
refIntegrityUpdate = checkForeignKeysAndDependentSide(inverseFieldDesc);
609         } else {
610             // Just check the dependent side.
611
refIntegrityUpdate = checkDependentSide(inverseFieldDesc);
612         }
613
614         if (!refIntegrityUpdate && cardinalityLWB == 1) {
615             // Lower bound should not be 1 in this case.
616
// We silently set it to 0 for now.
617
// RESOLVE: Shall we throw an exception here?
618
cardinalityLWB = 0;
619         }
620
621         return refIntegrityUpdate;
622     }
623
624     /**
625      * Checks, if one relationship side isn't mapped to primary key fields
626      * (i.e. foreign key side). Based on the assumption, that jointable
627      * relationships are always mapped to the primary key columns,
628      * this method is called for foreign relationships only.
629      *
630      * @param inverseFieldDesc Inverse relationship field.
631      * Is guaranteed to be not null!
632      * @return True, if datastore updates for this relationship will
633      * be scheduled locally, false otherwise.
634      */

635     private boolean checkForeignKeysAndDependentSide(ForeignFieldDesc inverseFieldDesc) {
636         boolean refIntegrityUpdate;
637
638         // Check the foreign keys.
639
if (checkForeignKey(getLocalFields())) {
640             // The foreign key is on the local side.
641
refIntegrityUpdate = true;
642         } else if (checkForeignKey(getForeignFields())) {
643             // The foreign key is on the other side.
644
refIntegrityUpdate = false;
645         } else {
646             // The relationship is mapped to primary key columns on either side.
647
refIntegrityUpdate = checkDependentSide(inverseFieldDesc);
648         }
649         return refIntegrityUpdate;
650     }
651
652     /**
653      * Marks the dependent side as identified by jdo meta-data for update.
654      * If no side is marked dependent, the following rules apply:
655      *
656      * <ul>
657      * <li>Foreign key relationships can be handled from both sides,
658      * because it must be an 1:1 relationship mapped to primary key
659      * fields.</li>
660      * <li>Jointable relationships need to be updated from exactly one
661      * side to implement unified dependency management. It's important to
662      * check the dependency on both relationship sides before the responsible
663      * side is chosen.</li>
664      * </ul>
665      *
666      * @param inverseFieldDesc Inverse relationship field.
667      * Is guaranteed to be not null!
668      * @return True, if datastore updates for this relationship will
669      * be scheduled locally, false otherwise.
670      * @see #isDependentOn
671      * @see SQLStateManager#manageDependencyForObjectField
672      */

673     private boolean checkDependentSide(ForeignFieldDesc inverseFieldDesc) {
674         boolean refIntegrityUpdate;
675
676         // Check if meta data identifies the dependent relationship side.
677
if (this.isDependentOn(inverseFieldDesc)) {
678             // This side is marked dependent and will be updated.
679
refIntegrityUpdate = true;
680         } else if (inverseFieldDesc.isDependentOn(this)) {
681             // This side is marked as primary, the other side will be updated.
682
refIntegrityUpdate = false;
683         } else {
684             if (!useJoinTable()) {
685                 // No information about the dependent side can be obtained and the
686
// relationship is mapped to the primary key fields on both sides.
687
// Relationship updates can be done from either side, but only during
688
// instance creation/deletion.
689
refIntegrityUpdate = true;
690             } else {
691                 // No information about the dependent side can be obtained. If
692
// the Employee-Insurance relationship is mapped to a jointable,
693
// the dependent side can't be determinated. Identifying the
694
// updated side is essential to provide unified dependency
695
// management for the database updates, see
696
// SQLStateManager#manageDependencyForObjectField
697
refIntegrityUpdate = chooseUpdatedSide(inverseFieldDesc);
698             }
699         }
700         return refIntegrityUpdate;
701     }
702
703     /**
704      * Checks if at least one of the fields in <code>fieldList</code>
705      * is updatable. In this case <code>fieldList</code> makes up a
706      * foreign key. This is based on the assumption, that key fields
707      * referred in relationships must not be updated. Not updatable fields
708      * have property REF_INTEGRITY_UPDATES unset.
709      *
710      * @param fieldList Fields corresponding to datastore columns.
711      * The fields are either a <code>ForeignFieldDesc</code>'s local or foreign fields.
712      * @return True, if <code>fieldList</code> is a foreign key, false otherwise.
713      */

714     private static boolean checkForeignKey(ArrayList JavaDoc fieldList) {
715         for (int i = 0; i < fieldList.size(); i++) {
716             FieldDesc lf = (FieldDesc) fieldList.get(i);
717
718             if ((lf.sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) > 0) {
719                 // Based on the assumption, that referred key fields
720
// have property REF_INTEGRITY_UPDATES unset, at least
721
// one of the fields is not part of the key.
722
return true;
723             }
724         }
725         return false;
726     }
727
728     /**
729      * Checks, if <code>this</code> relationship side is dependent
730      * on the inverse side <code>inverseFieldDesc</code>. The
731      * dependent side can be identified by the following criteria:
732      *
733      * <ul>
734      * <li>This side has cardinalityLWB == 1.</li>
735      * <li>The inverse side is marked for cascade delete.</li>
736      * </ul>
737      *
738      * @param inverseFieldDesc Inverse relationship field.
739      * Is guaranteed to be not null!
740      * @return true, if <code>this</code> relationship side is dependent
741      * on <code>inverseFieldDesc</code>, false otherwise.
742      */

743     private boolean isDependentOn(ForeignFieldDesc inverseFieldDesc) {
744         return (this.cardinalityLWB == 1 ||
745                 inverseFieldDesc.deleteAction == ForeignFieldDesc.ACT_CASCADE);
746     }
747
748     /**
749      * Choose the updated relationship side based on the alphabethical
750      * order of the related class names. For self relationships, the
751      * field names itself are compared, too.
752      *
753      * @param inverseFieldDesc Inverse relationship field.
754      * Is guaranteed to be not null!
755      * @return This method is guaranteed to identify the relationship
756      * side that will not be updated.
757      */

758     private boolean chooseUpdatedSide(ForeignFieldDesc inverseFieldDesc) {
759         int comparison = classDesc.getName().compareTo(foreignConfig.getName());
760
761         if (comparison == 0) {
762             comparison = getName().compareTo(inverseFieldDesc.getName());
763         }
764         return comparison < 0;
765     }
766
767     /**
768      * Unsets the REF_INTEGRITY_UPDATES property for this relationship field.
769      * Datastore updates will be scheduled on the opposite relationship side.
770      */

771     private void unsetReferentialIntegrityUpdateProperty() {
772         if (logger.isLoggable(Logger.FINEST)) {
773             logger.finest("sqlstore.model.classdesc.unsetrefintegrityupdate", getName()); // NOI18N
774
}
775
776         sqlProperties &= ~(FieldDesc.PROP_REF_INTEGRITY_UPDATES);
777     }
778
779     /**
780      * Unsets the IN_CONCURRENCY_CHECK property for all the
781      * (hidden) local fields involved in this relationship.
782      */

783     private void unsetConcurrencyCheckProperty() {
784         // Copy the field list temporarily.
785
ArrayList JavaDoc fieldList = (ArrayList JavaDoc) getLocalFields().clone();
786
787         if (useJoinTable()) {
788             fieldList.addAll(getAssocLocalFields());
789         }
790
791         for (int j = 0; j < fieldList.size(); j++) {
792             FieldDesc lf = (FieldDesc) fieldList.get(j);
793
794             if (lf.absoluteID < 0) {
795                 if (logger.isLoggable(Logger.FINEST)) {
796                     logger.finest("sqlstore.model.classdesc.unsetconcurrencychk", lf.getName()); // NOI18N
797
}
798                 lf.sqlProperties &= ~(FieldDesc.PROP_IN_CONCURRENCY_CHECK);
799             }
800         }
801     }
802
803 }
804
Popular Tags