1 23 24 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 ; 42 import java.util.ArrayList ; 43 44 47 public class ForeignFieldDesc extends FieldDesc { 48 49 54 public static final int ACT_CASCADE = RelationshipElement.CASCADE_ACTION; 55 56 60 public static final int ACT_NONE = RelationshipElement.NONE_ACTION; 61 62 63 public static final int ACT_NULLIFY = RelationshipElement.NULLIFY_ACTION; 64 65 66 public static final int ACT_RESTRICT = RelationshipElement.RESTRICT_ACTION; 67 68 69 public static final int ACT_AGGREGATE = RelationshipElement.AGGREGATE_ACTION; 70 71 72 public ClassDesc foreignConfig; 73 74 public int cardinalityLWB; 75 76 public int cardinalityUPB; 77 78 public int deleteAction; 80 81 82 public ArrayList foreignFields; 83 84 85 public ArrayList foreignColumns; 86 87 88 public ArrayList localFields; 89 90 91 public ArrayList localColumns; 92 93 94 public ArrayList assocForeignFields; 95 96 97 public ArrayList assocForeignColumns; 98 99 100 public ArrayList assocLocalFields; 101 102 103 public ArrayList assocLocalColumns; 104 105 109 private ForeignFieldDesc inverseRelationshipField; 110 111 115 private boolean isMappedToPk; 116 117 ForeignFieldDesc(ClassDesc config) { 118 super(config); 119 } 120 121 124 public boolean isRelationshipField() { 125 return true; 126 } 127 128 133 public boolean useJoinTable() { 134 return (assocLocalColumns != null && assocLocalColumns.size() > 0); 135 } 136 137 144 public boolean hasForeignKey() { 145 boolean result = false; 146 147 if (inverseRelationshipField != null) { 150 result = cardinalityUPB == 1 && !useJoinTable() && 151 (sqlProperties & FieldDesc.PROP_REF_INTEGRITY_UPDATES) > 0; 152 } 153 return result; 154 } 155 156 164 public boolean isMappedToPk() { 165 return isMappedToPk; 166 } 167 168 public ArrayList getLocalFields() { 169 if (localFields == null) { 170 localFields = new ArrayList (); 171 } 172 173 return localFields; 174 } 175 176 public ArrayList getForeignFields() { 177 if (foreignFields == null) { 178 foreignFields = new ArrayList (); 179 } 180 181 return foreignFields; 182 } 183 184 public ArrayList getAssocLocalFields() { 185 if (assocLocalFields == null && assocLocalColumns != null) { 188 assocLocalFields = new ArrayList (); 189 } 190 191 return assocLocalFields; 192 } 193 194 public ArrayList getAssocForeignFields() { 195 if (assocForeignFields == null && assocForeignColumns != null) { 198 assocForeignFields = new ArrayList (); 199 } 200 201 return assocForeignFields; 202 } 203 204 public ForeignFieldDesc getInverseRelationshipField() { 205 return inverseRelationshipField; 206 } 207 208 231 public Object createObjectId(SQLStateManager sm, LocalFieldDesc fieldDesc, Object value) { 232 233 assert isMappedToPk(); 234 235 Class oidClass = foreignConfig.getOidClass(); 236 Object oid = null; 237 238 try { 239 oid = oidClass.newInstance(); 240 } catch (Exception e) { 241 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 242 "core.statemanager.cantnewoid", oidClass.getName()), e); } 244 245 Field keyFields[] = foreignConfig.getKeyFields(); 246 String keyFieldNames[] = foreignConfig.getKeyFieldNames(); 247 for (int i = 0; i < keyFields.length && oid != null; i++) { 248 Field 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 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 keyField.set(oid, fa.convertValue(keyFieldValue, sm)); 270 } catch (IllegalAccessException e) { 271 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 272 "core.statemanager.cantsetkeyfield", keyField.getName()), e); } 274 } else { 275 oid = null; 276 } 277 } 278 } 279 } 280 281 return oid; 282 } 283 284 288 private void setInverseRelationshipField(ForeignFieldDesc f) { 290 inverseRelationshipField = f; 291 } 292 293 void computeTrackedRelationshipFields() { 294 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 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 330 void fixupForeignReference(ClassDesc foreignConfig, 331 ForeignFieldDesc inverseField) { 332 333 registerForeignConfig(foreignConfig, inverseField); 334 initializeFieldLists(); 335 initializeIsMappedToPk(); 336 addForeignKeyFieldsToDFG(); 337 } 338 339 345 private void registerForeignConfig(ClassDesc foreignConfig, 346 ForeignFieldDesc inverseField) { 347 boolean debug = logger.isLoggable(Logger.FINEST); 348 349 if (debug) { 350 Object [] items = new Object [] {classDesc, this, foreignConfig}; 351 logger.finest("sqlstore.model.classdesc.general", items); } 353 354 this.foreignConfig = foreignConfig; 356 357 if (debug && inverseField != null) { 358 logger.finest("sqlstore.model.classdesc.assocrelatedfield", inverseField); } 360 361 setInverseRelationshipField(inverseField); 362 } 363 364 367 private void initializeFieldLists() { 368 ClassDesc theConfig = classDesc; 369 370 for (int i = 0; i < 4; i++) { 371 ArrayList fields = null; 372 ArrayList 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")); } 404 405 fields.add(theConfig.getLocalFieldDesc(ce)); 406 } 407 } 408 } 409 410 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 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 448 void fixupFieldProperties() { 449 boolean refIntegrityUpdate = true; 450 451 if (cardinalityUPB > 1) { 452 if (!(refIntegrityUpdate = checkReferentialIntegrityUpdatesForCollectionField())) { 453 unsetReferentialIntegrityUpdateProperty(); 454 455 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 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 refIntegrityUpdate = false; 493 } else { 494 refIntegrityUpdate = defineUpdatedSideNToM(inverseFieldDesc); 499 } 500 } 501 return refIntegrityUpdate; 502 } 503 504 511 private boolean checkReferentialIntegrityUpdatesForObjectField() { 512 boolean refIntegrityUpdate; 513 ForeignFieldDesc inverseFieldDesc = getInverseRelationshipField(); 514 515 if (inverseFieldDesc == null) { 516 refIntegrityUpdate = true; 518 } else { 519 if (inverseFieldDesc.cardinalityUPB > 1) { 520 refIntegrityUpdate = true; 525 } else { 526 refIntegrityUpdate = defineUpdatedSide1To1(inverseFieldDesc); 532 } 533 } 534 return refIntegrityUpdate; 535 } 536 537 544 private boolean defineUpdatedSideXToM() { 545 boolean refIntegrityUpdate; 546 if (!useJoinTable()) { 547 refIntegrityUpdate = false; 551 } else { 552 refIntegrityUpdate = true; 554 } 555 return refIntegrityUpdate; 556 } 557 558 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 refIntegrityUpdate = true; 575 } else { 576 refIntegrityUpdate = chooseUpdatedSide(inverseFieldDesc); 577 } 578 return refIntegrityUpdate; 579 } 580 581 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 refIntegrityUpdate = true; 606 } else if (!useJoinTable()) { 607 refIntegrityUpdate = checkForeignKeysAndDependentSide(inverseFieldDesc); 609 } else { 610 refIntegrityUpdate = checkDependentSide(inverseFieldDesc); 612 } 613 614 if (!refIntegrityUpdate && cardinalityLWB == 1) { 615 cardinalityLWB = 0; 619 } 620 621 return refIntegrityUpdate; 622 } 623 624 635 private boolean checkForeignKeysAndDependentSide(ForeignFieldDesc inverseFieldDesc) { 636 boolean refIntegrityUpdate; 637 638 if (checkForeignKey(getLocalFields())) { 640 refIntegrityUpdate = true; 642 } else if (checkForeignKey(getForeignFields())) { 643 refIntegrityUpdate = false; 645 } else { 646 refIntegrityUpdate = checkDependentSide(inverseFieldDesc); 648 } 649 return refIntegrityUpdate; 650 } 651 652 673 private boolean checkDependentSide(ForeignFieldDesc inverseFieldDesc) { 674 boolean refIntegrityUpdate; 675 676 if (this.isDependentOn(inverseFieldDesc)) { 678 refIntegrityUpdate = true; 680 } else if (inverseFieldDesc.isDependentOn(this)) { 681 refIntegrityUpdate = false; 683 } else { 684 if (!useJoinTable()) { 685 refIntegrityUpdate = true; 690 } else { 691 refIntegrityUpdate = chooseUpdatedSide(inverseFieldDesc); 698 } 699 } 700 return refIntegrityUpdate; 701 } 702 703 714 private static boolean checkForeignKey(ArrayList 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 return true; 723 } 724 } 725 return false; 726 } 727 728 743 private boolean isDependentOn(ForeignFieldDesc inverseFieldDesc) { 744 return (this.cardinalityLWB == 1 || 745 inverseFieldDesc.deleteAction == ForeignFieldDesc.ACT_CASCADE); 746 } 747 748 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 771 private void unsetReferentialIntegrityUpdateProperty() { 772 if (logger.isLoggable(Logger.FINEST)) { 773 logger.finest("sqlstore.model.classdesc.unsetrefintegrityupdate", getName()); } 775 776 sqlProperties &= ~(FieldDesc.PROP_REF_INTEGRITY_UPDATES); 777 } 778 779 783 private void unsetConcurrencyCheckProperty() { 784 ArrayList fieldList = (ArrayList ) 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()); } 798 lf.sqlProperties &= ~(FieldDesc.PROP_IN_CONCURRENCY_CHECK); 799 } 800 } 801 } 802 803 } 804 | Popular Tags |