1 package xdoclet.modules.ojb.constraints; 2 3 17 18 import java.util.ArrayList ; 19 import java.util.Collection ; 20 import java.util.Iterator ; 21 22 import org.apache.commons.collections.SequencedHashMap; 23 24 import xdoclet.modules.ojb.CommaListIterator; 25 import xdoclet.modules.ojb.LogHelper; 26 import xdoclet.modules.ojb.model.ClassDescriptorDef; 27 import xdoclet.modules.ojb.model.CollectionDescriptorDef; 28 import xdoclet.modules.ojb.model.FeatureDescriptorDef; 29 import xdoclet.modules.ojb.model.FieldDescriptorDef; 30 import xdoclet.modules.ojb.model.ModelDef; 31 import xdoclet.modules.ojb.model.PropertyHelper; 32 import xdoclet.modules.ojb.model.ReferenceDescriptorDef; 33 34 40 public class ModelConstraints extends ConstraintsBase 41 { 42 49 public void check(ModelDef modelDef, String checkLevel) throws ConstraintException 50 { 51 ensureReferencedKeys(modelDef, checkLevel); 52 checkReferenceForeignkeys(modelDef, checkLevel); 53 checkCollectionForeignkeys(modelDef, checkLevel); 54 checkKeyModifications(modelDef, checkLevel); 55 } 56 57 67 private void ensureReferencedKeys(ModelDef modelDef, String checkLevel) throws ConstraintException 68 { 69 ClassDescriptorDef classDef; 70 CollectionDescriptorDef collDef; 71 ReferenceDescriptorDef refDef; 72 73 for (Iterator it = modelDef.getClasses(); it.hasNext();) 74 { 75 classDef = (ClassDescriptorDef)it.next(); 76 for (Iterator refIt = classDef.getReferences(); refIt.hasNext();) 77 { 78 refDef = (ReferenceDescriptorDef)refIt.next(); 79 if (!refDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_IGNORE, false)) 80 { 81 ensureReferencedPKs(modelDef, refDef); 82 } 83 } 84 for (Iterator collIt = classDef.getCollections(); collIt.hasNext();) 85 { 86 collDef = (CollectionDescriptorDef)collIt.next(); 87 if (!collDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_IGNORE, false)) 88 { 89 if (collDef.hasProperty(PropertyHelper.OJB_PROPERTY_INDIRECTION_TABLE)) 90 { 91 ensureReferencedPKs(modelDef, collDef); 92 } 93 else 94 { 95 ensureReferencedFKs(modelDef, collDef); 96 } 97 } 98 } 99 } 100 } 101 102 109 private void ensureReferencedPKs(ModelDef modelDef, ReferenceDescriptorDef refDef) throws ConstraintException 110 { 111 String targetClassName = refDef.getProperty(PropertyHelper.OJB_PROPERTY_CLASS_REF); 112 ClassDescriptorDef targetClassDef = modelDef.getClass(targetClassName); 113 114 ensurePKsFromHierarchy(targetClassDef); 115 } 116 117 125 private void ensureReferencedPKs(ModelDef modelDef, CollectionDescriptorDef collDef) throws ConstraintException 126 { 127 String elementClassName = collDef.getProperty(PropertyHelper.OJB_PROPERTY_ELEMENT_CLASS_REF); 128 ClassDescriptorDef elementClassDef = modelDef.getClass(elementClassName); 129 String indirTable = collDef.getProperty(PropertyHelper.OJB_PROPERTY_INDIRECTION_TABLE); 130 String localKey = collDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY); 131 String remoteKey = collDef.getProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY); 132 boolean hasRemoteKey = remoteKey != null; 133 ArrayList fittingCollections = new ArrayList (); 134 135 for (Iterator it = elementClassDef.getAllExtentClasses(); it.hasNext();) 138 { 139 ClassDescriptorDef subTypeDef = (ClassDescriptorDef)it.next(); 140 141 for (Iterator collIt = subTypeDef.getCollections(); collIt.hasNext();) 143 { 144 CollectionDescriptorDef curCollDef = (CollectionDescriptorDef)collIt.next(); 145 146 if (indirTable.equals(curCollDef.getProperty(PropertyHelper.OJB_PROPERTY_INDIRECTION_TABLE)) && 147 (collDef != curCollDef) && 148 (!hasRemoteKey || CommaListIterator.sameLists(remoteKey, curCollDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY))) && 149 (!curCollDef.hasProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY) || 150 CommaListIterator.sameLists(localKey, curCollDef.getProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY)))) 151 { 152 fittingCollections.add(curCollDef); 153 } 154 } 155 } 156 if (!fittingCollections.isEmpty()) 157 { 158 if (!hasRemoteKey && (fittingCollections.size() > 1)) 160 { 161 CollectionDescriptorDef firstCollDef = (CollectionDescriptorDef)fittingCollections.get(0); 162 String foreignKey = firstCollDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY); 163 164 for (int idx = 1; idx < fittingCollections.size(); idx++) 165 { 166 CollectionDescriptorDef curCollDef = (CollectionDescriptorDef)fittingCollections.get(idx); 167 168 if (!CommaListIterator.sameLists(foreignKey, curCollDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY))) 169 { 170 throw new ConstraintException("Cannot determine the element-side collection that corresponds to the collection "+ 171 collDef.getName()+" in type "+collDef.getOwner().getName()+ 172 " because there are at least two different collections that would fit."+ 173 " Specifying remote-foreignkey in the original collection "+collDef.getName()+ 174 " will perhaps help"); 175 } 176 } 177 collDef.setProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY, foreignKey); 179 for (int idx = 0; idx < fittingCollections.size(); idx++) 180 { 181 CollectionDescriptorDef curCollDef = (CollectionDescriptorDef)fittingCollections.get(idx); 182 183 curCollDef.setProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY, localKey); 184 } 185 } 186 } 187 188 ensurePKsFromHierarchy(elementClassDef); 190 } 191 192 199 private void ensureReferencedFKs(ModelDef modelDef, CollectionDescriptorDef collDef) throws ConstraintException 200 { 201 String elementClassName = collDef.getProperty(PropertyHelper.OJB_PROPERTY_ELEMENT_CLASS_REF); 202 ClassDescriptorDef elementClassDef = modelDef.getClass(elementClassName); 203 String fkFieldNames = collDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY); 204 ArrayList missingFields = new ArrayList (); 205 SequencedHashMap fkFields = new SequencedHashMap(); 206 207 for (CommaListIterator it = new CommaListIterator(fkFieldNames); it.hasNext();) 209 { 210 String fieldName = (String )it.next(); 211 FieldDescriptorDef fieldDef = elementClassDef.getField(fieldName); 212 213 if (fieldDef == null) 214 { 215 missingFields.add(fieldName); 216 } 217 fkFields.put(fieldName, fieldDef); 218 } 219 220 for (Iterator it = elementClassDef.getAllExtentClasses(); it.hasNext() && !missingFields.isEmpty();) 222 { 223 ClassDescriptorDef subTypeDef = (ClassDescriptorDef)it.next(); 224 225 for (int idx = 0; idx < missingFields.size();) 226 { 227 FieldDescriptorDef fieldDef = subTypeDef.getField((String )missingFields.get(idx)); 228 229 if (fieldDef != null) 230 { 231 fkFields.put(fieldDef.getName(), fieldDef); 232 missingFields.remove(idx); 233 } 234 else 235 { 236 idx++; 237 } 238 } 239 } 240 if (!missingFields.isEmpty()) 241 { 242 throw new ConstraintException("Cannot find field "+missingFields.get(0).toString()+" in the hierarchy with root type "+ 243 elementClassDef.getName()+" which is used as foreignkey in collection "+ 244 collDef.getName()+" in "+collDef.getOwner().getName()); 245 } 246 247 ensureFields(elementClassDef, fkFields.values()); 249 } 250 251 257 private void ensurePKsFromHierarchy(ClassDescriptorDef classDef) throws ConstraintException 258 { 259 SequencedHashMap pks = new SequencedHashMap(); 260 261 for (Iterator it = classDef.getAllExtentClasses(); it.hasNext();) 262 { 263 ClassDescriptorDef subTypeDef = (ClassDescriptorDef)it.next(); 264 265 ArrayList subPKs = subTypeDef.getPrimaryKeys(); 266 267 for (Iterator pkIt = subPKs.iterator(); pkIt.hasNext();) 269 { 270 FieldDescriptorDef fieldDef = (FieldDescriptorDef)pkIt.next(); 271 FieldDescriptorDef foundPKDef = (FieldDescriptorDef)pks.get(fieldDef.getName()); 272 273 if (foundPKDef != null) 274 { 275 if (!isEqual(fieldDef, foundPKDef)) 276 { 277 throw new ConstraintException("Cannot pull up the declaration of the required primary key "+fieldDef.getName()+ 278 " because its definitions in "+fieldDef.getOwner().getName()+" and "+ 279 foundPKDef.getOwner().getName()+" differ"); 280 } 281 } 282 else 283 { 284 pks.put(fieldDef.getName(), fieldDef); 285 } 286 } 287 } 288 289 ensureFields(classDef, pks.values()); 290 } 291 292 299 private void ensureFields(ClassDescriptorDef classDef, Collection fields) throws ConstraintException 300 { 301 boolean forceVirtual = !classDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_GENERATE_REPOSITORY_INFO, true); 302 303 for (Iterator it = fields.iterator(); it.hasNext();) 304 { 305 FieldDescriptorDef fieldDef = (FieldDescriptorDef)it.next(); 306 307 FieldDescriptorDef foundFieldDef = classDef.getField(fieldDef.getName()); 309 310 if (foundFieldDef != null) 311 { 312 if (isEqual(fieldDef, foundFieldDef)) 313 { 314 if (forceVirtual) 315 { 316 foundFieldDef.setProperty(PropertyHelper.OJB_PROPERTY_VIRTUAL_FIELD, "true"); 317 } 318 continue; 319 } 320 else 321 { 322 throw new ConstraintException("Cannot pull up the declaration of the required field "+fieldDef.getName()+ 323 " from type "+fieldDef.getOwner().getName()+" to basetype "+classDef.getName()+ 324 " because there is already a different field of the same name"); 325 } 326 } 327 328 if (classDef.getCollection(fieldDef.getName()) != null) 330 { 331 throw new ConstraintException("Cannot pull up the declaration of the required field "+fieldDef.getName()+ 332 " from type "+fieldDef.getOwner().getName()+" to basetype "+classDef.getName()+ 333 " because there is already a collection of the same name"); 334 } 335 if (classDef.getReference(fieldDef.getName()) != null) 336 { 337 throw new ConstraintException("Cannot pull up the declaration of the required field "+fieldDef.getName()+ 338 " from type "+fieldDef.getOwner().getName()+" to basetype "+classDef.getName()+ 339 " because there is already a reference of the same name"); 340 } 341 classDef.addFieldClone(fieldDef); 342 classDef.getField(fieldDef.getName()).setProperty(PropertyHelper.OJB_PROPERTY_VIRTUAL_FIELD, "true"); 343 } 344 } 345 346 354 private boolean isEqual(FieldDescriptorDef first, FieldDescriptorDef second) 355 { 356 return first.getName().equals(second.getName()) && 357 first.getProperty(PropertyHelper.OJB_PROPERTY_COLUMN).equals(second.getProperty(PropertyHelper.OJB_PROPERTY_COLUMN)) && 358 first.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE).equals(second.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE)); 359 } 360 361 368 private void checkCollectionForeignkeys(ModelDef modelDef, String checkLevel) throws ConstraintException 369 { 370 if (CHECKLEVEL_NONE.equals(checkLevel)) 371 { 372 return; 373 } 374 375 ClassDescriptorDef classDef; 376 CollectionDescriptorDef collDef; 377 378 for (Iterator it = modelDef.getClasses(); it.hasNext();) 379 { 380 classDef = (ClassDescriptorDef)it.next(); 381 for (Iterator collIt = classDef.getCollections(); collIt.hasNext();) 382 { 383 collDef = (CollectionDescriptorDef)collIt.next(); 384 if (!collDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_IGNORE, false)) 385 { 386 if (collDef.hasProperty(PropertyHelper.OJB_PROPERTY_INDIRECTION_TABLE)) 387 { 388 checkIndirectionTable(modelDef, collDef); 389 } 390 else 391 { 392 checkCollectionForeignkeys(modelDef, collDef); 393 } 394 } 395 } 396 } 397 } 398 399 407 private void checkIndirectionTable(ModelDef modelDef, CollectionDescriptorDef collDef) throws ConstraintException 408 { 409 String foreignkey = collDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY); 410 411 if ((foreignkey == null) || (foreignkey.length() == 0)) 412 { 413 throw new ConstraintException("The collection "+collDef.getName()+" in class "+collDef.getOwner().getName()+" has no foreignkeys"); 414 } 415 416 String elementClassName = collDef.getProperty(PropertyHelper.OJB_PROPERTY_ELEMENT_CLASS_REF); 420 ClassDescriptorDef elementClass = modelDef.getClass(elementClassName); 421 CollectionDescriptorDef remoteCollDef = collDef.getRemoteCollection(); 422 423 if (remoteCollDef == null) 424 { 425 if (!collDef.hasProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY)) 427 { 428 throw new ConstraintException("The collection "+collDef.getName()+" in class "+collDef.getOwner().getName()+" must specify remote-foreignkeys as the class on the other side of the m:n association has no corresponding collection"); 429 } 430 } 431 else 432 { 433 String remoteKeys2 = remoteCollDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY); 434 435 if (collDef.hasProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY)) 436 { 437 String remoteKeys1 = collDef.getProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY); 439 440 if (!CommaListIterator.sameLists(remoteKeys1, remoteKeys2)) 441 { 442 throw new ConstraintException("The remote-foreignkey property specified for collection "+collDef.getName()+" in class "+collDef.getOwner().getName()+" doesn't match the foreignkey property of the corresponding collection "+remoteCollDef.getName()+" in class "+elementClass.getName()); 443 } 444 } 445 else 446 { 447 collDef.setProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY, remoteKeys2); 449 } 450 } 451 452 String remoteForeignkey = collDef.getProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY); 454 455 if (CommaListIterator.sameLists(foreignkey, remoteForeignkey)) 456 { 457 LogHelper.warn(true, 458 getClass(), 459 "checkIndirectionTable", 460 "The remote foreignkey ("+remoteForeignkey+") for the collection "+collDef.getName()+" in class "+collDef.getOwner().getName()+" is identical (ignoring case) to the foreign key ("+foreignkey+")."); 461 } 462 463 if (collDef.getOriginal() != null) 466 { 467 CollectionDescriptorDef origDef = (CollectionDescriptorDef)collDef.getOriginal(); 468 CollectionDescriptorDef origRemoteDef = origDef.getRemoteCollection(); 469 470 origDef.setProperty(PropertyHelper.TORQUE_PROPERTY_RELATION_NAME, null); 472 origDef.setProperty(PropertyHelper.TORQUE_PROPERTY_INV_RELATION_NAME, null); 473 if (origRemoteDef != null) 474 { 475 origRemoteDef.setProperty(PropertyHelper.TORQUE_PROPERTY_RELATION_NAME, null); 476 origRemoteDef.setProperty(PropertyHelper.TORQUE_PROPERTY_INV_RELATION_NAME, null); 477 } 478 } 479 else if (!collDef.hasProperty(PropertyHelper.TORQUE_PROPERTY_RELATION_NAME)) 480 { 481 if (remoteCollDef == null) 482 { 483 collDef.setProperty(PropertyHelper.TORQUE_PROPERTY_RELATION_NAME, collDef.getName()); 484 collDef.setProperty(PropertyHelper.TORQUE_PROPERTY_INV_RELATION_NAME, "inverse "+collDef.getName()); 485 } 486 else 487 { 488 String relName = collDef.getName()+"-"+remoteCollDef.getName(); 489 490 collDef.setProperty(PropertyHelper.TORQUE_PROPERTY_RELATION_NAME, relName); 491 remoteCollDef.setProperty(PropertyHelper.TORQUE_PROPERTY_INV_RELATION_NAME, relName); 492 493 relName = remoteCollDef.getName()+"-"+collDef.getName(); 494 495 collDef.setProperty(PropertyHelper.TORQUE_PROPERTY_INV_RELATION_NAME, relName); 496 remoteCollDef.setProperty(PropertyHelper.TORQUE_PROPERTY_RELATION_NAME, relName); 497 } 498 } 499 } 500 501 508 private void checkCollectionForeignkeys(ModelDef modelDef, CollectionDescriptorDef collDef) throws ConstraintException 509 { 510 String foreignkey = collDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY); 511 512 if ((foreignkey == null) || (foreignkey.length() == 0)) 513 { 514 throw new ConstraintException("The collection "+collDef.getName()+" in class "+collDef.getOwner().getName()+" has no foreignkeys"); 515 } 516 517 String remoteForeignkey = collDef.getProperty(PropertyHelper.OJB_PROPERTY_REMOTE_FOREIGNKEY); 518 519 if ((remoteForeignkey != null) && (remoteForeignkey.length() > 0)) 520 { 521 LogHelper.warn(true, 523 getClass(), 524 "checkCollectionForeignkeys", 525 "For the collection "+collDef.getName()+" in class "+collDef.getOwner().getName()+", a remote foreignkey was specified though it is a 1:n, not a m:n collection"); 526 } 527 528 ClassDescriptorDef ownerClass = (ClassDescriptorDef)collDef.getOwner(); 529 ArrayList primFields = ownerClass.getPrimaryKeys(); 530 String elementClassName = collDef.getProperty(PropertyHelper.OJB_PROPERTY_ELEMENT_CLASS_REF); 531 ArrayList queue = new ArrayList (); 532 ClassDescriptorDef elementClass; 533 ArrayList keyFields; 534 FieldDescriptorDef keyField; 535 FieldDescriptorDef primField; 536 String primType; 537 String keyType; 538 539 queue.add(modelDef.getClass(elementClassName)); 541 while (!queue.isEmpty()) 542 { 543 elementClass = (ClassDescriptorDef)queue.get(0); 544 queue.remove(0); 545 546 for (Iterator it = elementClass.getExtentClasses(); it.hasNext();) 547 { 548 queue.add(it.next()); 549 } 550 if (!elementClass.getBooleanProperty(PropertyHelper.OJB_PROPERTY_GENERATE_REPOSITORY_INFO, true)) 551 { 552 continue; 553 } 554 try 555 { 556 keyFields = elementClass.getFields(foreignkey); 557 } 558 catch (NoSuchFieldException ex) 559 { 560 throw new ConstraintException("The collection "+collDef.getName()+" in class "+collDef.getOwner().getName()+" specifies a foreignkey "+ex.getMessage()+" that is not a persistent field in the element class (or its subclass) "+elementClass.getName()); 561 } 562 if (primFields.size() != keyFields.size()) 563 { 564 throw new ConstraintException("The number of foreignkeys ("+keyFields.size()+") of the collection "+collDef.getName()+" in class "+collDef.getOwner().getName()+" doesn't match the number of primarykeys ("+primFields.size()+") of its owner class "+ownerClass.getName()); 565 } 566 for (int idx = 0; idx < keyFields.size(); idx++) 567 { 568 keyField = (FieldDescriptorDef)keyFields.get(idx); 569 if (keyField.getBooleanProperty(PropertyHelper.OJB_PROPERTY_IGNORE, false)) 570 { 571 throw new ConstraintException("The collection "+collDef.getName()+" in class "+ownerClass.getName()+" uses the field "+keyField.getName()+" as foreignkey although this field is ignored in the element class (or its subclass) "+elementClass.getName()); 572 } 573 } 574 for (int idx = 0; idx < primFields.size(); idx++) 576 { 577 keyField = (FieldDescriptorDef)keyFields.get(idx); 578 if (keyField.getBooleanProperty(PropertyHelper.OJB_PROPERTY_IGNORE, false)) 579 { 580 throw new ConstraintException("The collection "+collDef.getName()+" in class "+ownerClass.getName()+" uses the field "+keyField.getName()+" as foreignkey although this field is ignored in the element class (or its subclass) "+elementClass.getName()); 581 } 582 primField = (FieldDescriptorDef)primFields.get(idx); 583 primType = primField.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE); 584 keyType = keyField.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE); 585 if (!primType.equals(keyType)) 586 { 587 throw new ConstraintException("The jdbc-type of foreignkey "+keyField.getName()+" in the element class (or its subclass) "+elementClass.getName()+" used by the collection "+collDef.getName()+" in class "+ownerClass.getName()+" doesn't match the jdbc-type of the corresponding primarykey "+primField.getName()); 588 } 589 } 590 } 591 } 592 593 600 private void checkReferenceForeignkeys(ModelDef modelDef, String checkLevel) throws ConstraintException 601 { 602 if (CHECKLEVEL_NONE.equals(checkLevel)) 603 { 604 return; 605 } 606 607 ClassDescriptorDef classDef; 608 ReferenceDescriptorDef refDef; 609 610 for (Iterator it = modelDef.getClasses(); it.hasNext();) 611 { 612 classDef = (ClassDescriptorDef)it.next(); 613 for (Iterator refIt = classDef.getReferences(); refIt.hasNext();) 614 { 615 refDef = (ReferenceDescriptorDef)refIt.next(); 616 if (!refDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_IGNORE, false)) 617 { 618 checkReferenceForeignkeys(modelDef, refDef); 619 } 620 } 621 } 622 } 623 624 631 private void checkReferenceForeignkeys(ModelDef modelDef, ReferenceDescriptorDef refDef) throws ConstraintException 632 { 633 String foreignkey = refDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY); 634 635 if ((foreignkey == null) || (foreignkey.length() == 0)) 636 { 637 throw new ConstraintException("The reference "+refDef.getName()+" in class "+refDef.getOwner().getName()+" has no foreignkeys"); 638 } 639 640 ClassDescriptorDef ownerClass = (ClassDescriptorDef)refDef.getOwner(); 642 ArrayList keyFields; 643 FieldDescriptorDef keyField; 644 645 try 646 { 647 keyFields = ownerClass.getFields(foreignkey); 648 } 649 catch (NoSuchFieldException ex) 650 { 651 throw new ConstraintException("The reference "+refDef.getName()+" in class "+refDef.getOwner().getName()+" specifies a foreignkey "+ex.getMessage()+" that is not a persistent field in its owner class "+ownerClass.getName()); 652 } 653 for (int idx = 0; idx < keyFields.size(); idx++) 654 { 655 keyField = (FieldDescriptorDef)keyFields.get(idx); 656 if (keyField.getBooleanProperty(PropertyHelper.OJB_PROPERTY_IGNORE, false)) 657 { 658 throw new ConstraintException("The reference "+refDef.getName()+" in class "+ownerClass.getName()+" uses the field "+keyField.getName()+" as foreignkey although this field is ignored in this class"); 659 } 660 } 661 662 String targetClassName = refDef.getProperty(PropertyHelper.OJB_PROPERTY_CLASS_REF); 666 ArrayList queue = new ArrayList (); 667 ClassDescriptorDef referencedClass; 668 ArrayList primFields; 669 FieldDescriptorDef primField; 670 String primType; 671 String keyType; 672 673 queue.add(modelDef.getClass(targetClassName)); 674 675 while (!queue.isEmpty()) 676 { 677 referencedClass = (ClassDescriptorDef)queue.get(0); 678 queue.remove(0); 679 680 for (Iterator it = referencedClass.getExtentClasses(); it.hasNext();) 681 { 682 queue.add(it.next()); 683 } 684 if (!referencedClass.getBooleanProperty(PropertyHelper.OJB_PROPERTY_GENERATE_REPOSITORY_INFO, true)) 685 { 686 continue; 687 } 688 primFields = referencedClass.getPrimaryKeys(); 689 if (primFields.size() != keyFields.size()) 690 { 691 throw new ConstraintException("The number of foreignkeys ("+keyFields.size()+") of the reference "+refDef.getName()+" in class "+refDef.getOwner().getName()+" doesn't match the number of primarykeys ("+primFields.size()+") of the referenced class (or its subclass) "+referencedClass.getName()); 692 } 693 for (int idx = 0; idx < primFields.size(); idx++) 694 { 695 keyField = (FieldDescriptorDef)keyFields.get(idx); 696 primField = (FieldDescriptorDef)primFields.get(idx); 697 primType = primField.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE); 698 keyType = keyField.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE); 699 if (!primType.equals(keyType)) 700 { 701 throw new ConstraintException("The jdbc-type of foreignkey "+keyField.getName()+" of the reference "+refDef.getName()+" in class "+refDef.getOwner().getName()+" doesn't match the jdbc-type of the corresponding primarykey "+primField.getName()+" of the referenced class (or its subclass) "+referencedClass.getName()); 702 } 703 } 704 } 705 } 706 707 715 private void checkKeyModifications(ModelDef modelDef, String checkLevel) throws ConstraintException 716 { 717 if (CHECKLEVEL_NONE.equals(checkLevel)) 718 { 719 return; 720 } 721 722 ClassDescriptorDef classDef; 723 FieldDescriptorDef fieldDef; 724 725 for (Iterator classIt = modelDef.getClasses(); classIt.hasNext();) 727 { 728 classDef = (ClassDescriptorDef)classIt.next(); 729 for (Iterator fieldIt = classDef.getFields(); fieldIt.hasNext();) 730 { 731 fieldDef = (FieldDescriptorDef)fieldIt.next(); 732 if (fieldDef.isInherited()) 733 { 734 checkKeyModifications(modelDef, fieldDef); 735 } 736 } 737 } 738 } 739 740 747 private void checkKeyModifications(ModelDef modelDef, FieldDescriptorDef keyDef) throws ConstraintException 748 { 749 FieldDescriptorDef baseFieldDef = (FieldDescriptorDef)keyDef.getOriginal(); 751 boolean isIgnored = keyDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_IGNORE, false); 752 boolean changesJdbcType = !baseFieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE).equals(keyDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE)); 753 boolean changesPrimary = baseFieldDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_PRIMARYKEY, false) != 754 keyDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_PRIMARYKEY, false) ; 755 756 if (isIgnored || changesJdbcType || changesPrimary) 757 { 758 FeatureDescriptorDef usingFeature = null; 759 760 do 761 { 762 usingFeature = usedByReference(modelDef, baseFieldDef); 763 if (usingFeature != null) 764 { 765 if (isIgnored) 766 { 767 throw new ConstraintException("Cannot ignore field "+keyDef.getName()+" in class "+keyDef.getOwner().getName()+ 768 " because it is used in class "+baseFieldDef.getOwner().getName()+ 769 " by the reference "+usingFeature.getName()+" from class "+ 770 usingFeature.getOwner().getName()); 771 } 772 else if (changesJdbcType) 773 { 774 throw new ConstraintException("Modification of the jdbc-type for the field "+keyDef.getName()+" in class "+ 775 keyDef.getOwner().getName()+" is not allowed because it is used in class "+ 776 baseFieldDef.getOwner().getName()+" by the reference "+usingFeature.getName()+ 777 " from class "+usingFeature.getOwner().getName()); 778 } 779 else 780 { 781 throw new ConstraintException("Cannot change the primarykey status of field "+keyDef.getName()+" in class "+ 782 keyDef.getOwner().getName()+" as primarykeys are used in class "+ 783 baseFieldDef.getOwner().getName()+" by the reference "+usingFeature.getName()+ 784 " from class "+usingFeature.getOwner().getName()); 785 } 786 } 787 788 usingFeature = usedByCollection(modelDef, baseFieldDef, changesPrimary); 789 if (usingFeature != null) 790 { 791 if (isIgnored) 792 { 793 throw new ConstraintException("Cannot ignore field "+keyDef.getName()+" in class "+keyDef.getOwner().getName()+ 794 " because it is used in class "+baseFieldDef.getOwner().getName()+ 795 " as a foreignkey of the collection "+usingFeature.getName()+" from class "+ 796 usingFeature.getOwner().getName()); 797 } 798 else if (changesJdbcType) 799 { 800 throw new ConstraintException("Modification of the jdbc-type for the field "+keyDef.getName()+" in class "+ 801 keyDef.getOwner().getName()+" is not allowed because it is used in class "+ 802 baseFieldDef.getOwner().getName()+" as a foreignkey of the collecton "+ 803 usingFeature.getName()+" from class "+usingFeature.getOwner().getName()); 804 } 805 else 806 { 807 throw new ConstraintException("Cannot change the primarykey status of field "+keyDef.getName()+" in class "+ 808 keyDef.getOwner().getName()+" as primarykeys are used in class "+ 809 baseFieldDef.getOwner().getName()+" by the collection "+usingFeature.getName()+ 810 " from class "+usingFeature.getOwner().getName()); 811 } 812 } 813 814 baseFieldDef = (FieldDescriptorDef)baseFieldDef.getOriginal(); 815 } 816 while (baseFieldDef != null); 817 } 818 } 819 820 831 private CollectionDescriptorDef usedByCollection(ModelDef modelDef, FieldDescriptorDef fieldDef, boolean elementClassSuffices) 832 { 833 ClassDescriptorDef ownerClass = (ClassDescriptorDef)fieldDef.getOwner(); 834 String ownerClassName = ownerClass.getQualifiedName(); 835 String name = fieldDef.getName(); 836 ClassDescriptorDef classDef; 837 CollectionDescriptorDef collDef; 838 String elementClassName; 839 840 for (Iterator classIt = modelDef.getClasses(); classIt.hasNext();) 841 { 842 classDef = (ClassDescriptorDef)classIt.next(); 843 for (Iterator collIt = classDef.getCollections(); collIt.hasNext();) 844 { 845 collDef = (CollectionDescriptorDef)collIt.next(); 846 elementClassName = collDef.getProperty(PropertyHelper.OJB_PROPERTY_ELEMENT_CLASS_REF).replace('$', '.'); 847 if (ownerClassName.equals(elementClassName)) 850 { 851 if (collDef.hasProperty(PropertyHelper.OJB_PROPERTY_INDIRECTION_TABLE)) 852 { 853 if (elementClassSuffices) 854 { 855 return collDef; 856 } 857 } 858 else if (new CommaListIterator(collDef.getProperty(PropertyHelper.OJB_PROPERTY_FOREIGNKEY)).contains(name)) 859 { 860 return collDef; 862 } 863 } 864 } 865 } 866 return null; 867 } 868 869 877 private ReferenceDescriptorDef usedByReference(ModelDef modelDef, FieldDescriptorDef fieldDef) 878 { 879 String ownerClassName = ((ClassDescriptorDef)fieldDef.getOwner()).getQualifiedName(); 880 ClassDescriptorDef classDef; 881 ReferenceDescriptorDef refDef; 882 String targetClassName; 883 884 if (PropertyHelper.toBoolean(fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_PRIMARYKEY), false)) 886 { 887 for (Iterator classIt = modelDef.getClasses(); classIt.hasNext();) 888 { 889 classDef = (ClassDescriptorDef)classIt.next(); 890 for (Iterator refIt = classDef.getReferences(); refIt.hasNext();) 891 { 892 refDef = (ReferenceDescriptorDef)refIt.next(); 893 targetClassName = refDef.getProperty(PropertyHelper.OJB_PROPERTY_CLASS_REF).replace('$', '.'); 894 if (ownerClassName.equals(targetClassName)) 895 { 896 return refDef; 898 } 899 } 900 } 901 } 902 return null; 903 } 904 } 905 | Popular Tags |