001/** 002 * Copyright 2005-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.service.impl; 017 018import java.beans.PropertyDescriptor; 019import java.lang.reflect.InvocationTargetException; 020import java.util.ArrayList; 021import java.util.Collection; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import java.util.Vector; 027 028import org.apache.commons.beanutils.PropertyUtils; 029import org.apache.commons.lang.StringUtils; 030import org.apache.ojb.broker.metadata.ClassDescriptor; 031import org.apache.ojb.broker.metadata.CollectionDescriptor; 032import org.apache.ojb.broker.metadata.FieldDescriptor; 033import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; 034import org.apache.ojb.broker.metadata.SuperReferenceDescriptor; 035import org.kuali.rice.krad.bo.DataObjectRelationship; 036import org.kuali.rice.krad.bo.PersistableBusinessObject; 037import org.kuali.rice.krad.bo.PersistableBusinessObjectBaseAdapter; 038import org.kuali.rice.krad.exception.ClassNotPersistableException; 039import org.kuali.rice.krad.exception.IntrospectionException; 040import org.kuali.rice.krad.exception.ObjectNotABusinessObjectRuntimeException; 041import org.kuali.rice.krad.exception.ReferenceAttributeDoesntExistException; 042import org.kuali.rice.krad.exception.ReferenceAttributeNotAnOjbReferenceException; 043import org.kuali.rice.krad.service.PersistenceStructureService; 044import org.kuali.rice.krad.util.ForeignKeyFieldsPopulationState; 045import org.kuali.rice.krad.util.LegacyDataFramework; 046@Deprecated 047@LegacyDataFramework 048public class PersistenceStructureServiceOjbImpl extends PersistenceServiceImplBase implements PersistenceStructureService { 049 050 /** 051 * 052 * special case when the attributeClass passed in doesnt match the class of 053 * the reference-descriptor as defined in ojb-repository. Currently the only 054 * case of this happening is ObjectCode vs. ObjectCodeCurrent. 055 * 056 * NOTE: This method makes no real sense and is a product of a hack 057 * introduced by KFS for an unknown reason. If you find yourself using this 058 * map stop and go do something else. 059 * 060 * @param from 061 * the class in the code 062 * @param to 063 * the class in the repository 064 */ 065 public static Map<Class, Class> referenceConversionMap = new HashMap<Class, Class>(); 066 067 068 private PersistenceStructureService persistenceStructureServiceJpa; 069 070 public PersistenceStructureService getPersistenceStructureServiceJpa() { 071 return this.persistenceStructureServiceJpa; 072 } 073 074 public void setPersistenceStructureServiceJpa(PersistenceStructureService persistenceStructureServiceJpa) { 075 this.persistenceStructureServiceJpa = persistenceStructureServiceJpa; 076 } 077 078 /** 079 * @see org.kuali.rice.krad.service.PersistenceService#isPersistable(java.lang.Class) 080 */ 081 082 @Override 083 public boolean isPersistable(Class clazz) { 084 boolean isPersistable = false; 085 try { 086 if (getClassDescriptor(clazz) != null) { 087 isPersistable = true; 088 } 089 } catch (ClassNotPersistableException e) { 090 isPersistable = false; 091 } 092 return isPersistable; 093 } 094 095 /** 096 * @see org.kuali.rice.krad.service.PersistenceService#getPrimaryKeys(java.lang.Class) 097 */ 098 099 @Override 100 public List getPrimaryKeys(Class clazz) { 101 List pkList = new ArrayList(); 102 ClassDescriptor classDescriptor = getClassDescriptor(clazz); 103 FieldDescriptor keyDescriptors[] = classDescriptor.getPkFields(); 104 for (int i = 0; i < keyDescriptors.length; ++i) { 105 FieldDescriptor keyDescriptor = keyDescriptors[i]; 106 pkList.add(keyDescriptor.getAttributeName()); 107 } 108 return pkList; 109 } 110 111 /** 112 * @see org.kuali.rice.krad.service.PersistenceMetadataExplorerService#listFieldNames(java.lang.Class) 113 */ 114 115 @Override 116 public List listFieldNames(Class clazz) { 117 List fieldNames = new ArrayList(); 118 ClassDescriptor classDescriptor = getClassDescriptor(clazz); 119 FieldDescriptor fieldDescriptors[] = classDescriptor.getFieldDescriptions(); 120 for (int i = 0; i < fieldDescriptors.length; ++i) { 121 FieldDescriptor fieldDescriptor = fieldDescriptors[i]; 122 fieldNames.add(fieldDescriptor.getAttributeName()); 123 } 124 return fieldNames; 125 } 126 127 /** 128 * @see org.kuali.rice.krad.service.PersistenceMetadataService#clearPrimaryKeyFields(java.lang.Object) 129 */ 130 // Unit tests only 131 @Override 132 public Object clearPrimaryKeyFields(Object persistableObject) { 133 if (persistableObject == null) { 134 throw new IllegalArgumentException("invalid (null) persistableObject"); 135 } 136 137 String className = null; 138 String fieldName = null; 139 try { 140 className = persistableObject.getClass().getName(); 141 List fields = listPrimaryKeyFieldNames(persistableObject.getClass()); 142 for (Iterator i = fields.iterator(); i.hasNext();) { 143 fieldName = (String) i.next(); 144 145 PropertyUtils.setProperty(persistableObject, fieldName, null); 146 } 147 148 if (persistableObject instanceof PersistableBusinessObject) { 149 ((PersistableBusinessObject) persistableObject).setObjectId(null); 150 } 151 } catch (NoSuchMethodException e) { 152 throw new IntrospectionException("no setter for property '" + className + "." + fieldName + "'", e); 153 } catch (IllegalAccessException e) { 154 throw new IntrospectionException("problem accessing property '" + className + "." + fieldName + "'", e); 155 } catch (InvocationTargetException e) { 156 throw new IntrospectionException("problem invoking getter for property '" + className + "." + fieldName + "'", e); 157 } 158 159 return persistableObject; 160 } 161 162 /** 163 * @see org.kuali.rice.krad.service.PersistenceMetadataExplorerService#listPersistableSubclasses(java.lang.Class) 164 */ 165 166 // Unit tests only 167 @Override 168 public List listPersistableSubclasses(Class superclazz) { 169 if (superclazz == null) { 170 throw new IllegalArgumentException("invalid (null) uberclass"); 171 } 172 173 Map allDescriptors = getDescriptorRepository().getDescriptorTable(); 174 List persistableSubclasses = new ArrayList(); 175 for (Iterator i = allDescriptors.entrySet().iterator(); i.hasNext();) { 176 Map.Entry e = (Map.Entry) i.next(); 177 178 Class persistableClass = ((ClassDescriptor) e.getValue()).getClassOfObject(); 179 if (!superclazz.equals(persistableClass) && superclazz.isAssignableFrom(persistableClass)) { 180 persistableSubclasses.add(persistableClass); 181 } 182 } 183 return persistableSubclasses; 184 } 185 186 /** 187 * @see org.kuali.rice.krad.service.PersistenceService#getRelationshipMetadata(java.lang.Class, 188 * java.lang.String) 189 */ 190 191 @Override 192 public Map<String, DataObjectRelationship> getRelationshipMetadata(Class persistableClass, String attributeName, String attributePrefix) { 193 if (persistableClass == null) { 194 throw new IllegalArgumentException("invalid (null) persistableClass"); 195 } 196 if (StringUtils.isBlank(attributeName)) { 197 throw new IllegalArgumentException("invalid (blank) attributeName"); 198 } 199 200 Map<String, DataObjectRelationship> relationships = new HashMap<String, DataObjectRelationship>(); 201 ClassDescriptor classDescriptor = getClassDescriptor(persistableClass); 202 Vector<ObjectReferenceDescriptor> references = classDescriptor.getObjectReferenceDescriptors(); 203 for (ObjectReferenceDescriptor objRef : references) { 204 Vector fks = objRef.getForeignKeyFields(); 205 if (fks.contains(attributeName) || objRef.getAttributeName().equals(attributeName)) { 206 Map<String, String> fkToPkRefs = getForeignKeysForReference(persistableClass, objRef.getAttributeName()); 207 DataObjectRelationship rel = new DataObjectRelationship(persistableClass, objRef.getAttributeName(), objRef.getItemClass()); 208 for (Map.Entry<String, String> ref : fkToPkRefs.entrySet()) { 209 if (StringUtils.isBlank(attributePrefix)) { 210 rel.getParentToChildReferences().put(ref.getKey(), ref.getValue()); 211 } else { 212 rel.getParentToChildReferences().put(attributePrefix + "." + ref.getKey(), ref.getValue()); 213 } 214 } 215 relationships.put(objRef.getAttributeName(), rel); 216 } 217 } 218 return relationships; 219 } 220 221 222 // Unit tests only 223 @Override 224 public Map<String, DataObjectRelationship> getRelationshipMetadata(Class persistableClass, String attributeName) { 225 return getRelationshipMetadata(persistableClass, attributeName, null); 226 } 227 228 /** 229 * @see org.kuali.rice.krad.service.PersistenceService#getForeignKeyFieldName(java.lang.Object, 230 * java.lang.String, java.lang.String) 231 */ 232 233 @Override 234 public String getForeignKeyFieldName(Class persistableObjectClass, String attributeName, String pkName) { 235 String fkName = ""; 236 ClassDescriptor classDescriptor = getClassDescriptor(persistableObjectClass); 237 ObjectReferenceDescriptor objectReferenceDescriptor = classDescriptor.getObjectReferenceDescriptorByName(attributeName); 238 if (objectReferenceDescriptor == null) { 239 throw new RuntimeException("Attribute name " + attributeName + " is not a valid reference to class " + persistableObjectClass.getName()); 240 } 241 ClassDescriptor referenceDescriptor = this.getClassDescriptor(objectReferenceDescriptor.getItemClass()); 242 243 FieldDescriptor[] fkFields = objectReferenceDescriptor.getForeignKeyFieldDescriptors(classDescriptor); 244 FieldDescriptor[] pkFields = referenceDescriptor.getPkFields(); 245 for (int i = 0; i < pkFields.length; i++) { 246 FieldDescriptor pkField = pkFields[i]; 247 if (pkField.getAttributeName().equals(pkName)) { 248 fkName = fkFields[i].getAttributeName(); 249 } 250 } 251 return fkName; 252 } 253 254 /** 255 * @see org.kuali.rice.krad.service.PersistenceService#getReferencesForForeignKey(java.lang.Class, 256 * java.lang.String) 257 */ 258 259 @Override 260 public Map getReferencesForForeignKey(Class persistableObjectClass, String attributeName) { 261 Map referenceClasses = new HashMap(); 262 if (PersistableBusinessObject.class.isAssignableFrom(persistableObjectClass)) { 263 ClassDescriptor classDescriptor = getClassDescriptor(persistableObjectClass); 264 Vector objectReferences = classDescriptor.getObjectReferenceDescriptors(); 265 for (Iterator iter = objectReferences.iterator(); iter.hasNext();) { 266 ObjectReferenceDescriptor referenceDescriptor = (ObjectReferenceDescriptor) iter.next(); 267 268 /* 269 * iterate through the fk keys for the reference object and if 270 * matches the attributeName add the class as a reference 271 */ 272 FieldDescriptor[] refFkNames = referenceDescriptor.getForeignKeyFieldDescriptors(classDescriptor); 273 for (int i = 0; i < refFkNames.length; i++) { 274 FieldDescriptor fkField = refFkNames[i]; 275 if (fkField.getAttributeName().equals(attributeName)) { 276 referenceClasses.put(referenceDescriptor.getAttributeName(), referenceDescriptor.getItemClass()); 277 } 278 } 279 } 280 } 281 return referenceClasses; 282 } 283 284 /** 285 * @see org.kuali.rice.krad.service.PersistenceService#getForeignKeysForReference(java.lang.Class, 286 * java.lang.String) The Map structure is: Key(String fkFieldName) => 287 * Value(String pkFieldName) NOTE that this implementation depends on 288 * the ordering of foreign-key elements in the ojb-repository matching 289 * the ordering of primary-key declarations of the class on the other 290 * side of the relationship. This is done because: 1. The current 291 * version of OJB requires you to declare all of these things in the 292 * correct (and matching) order in the ojb-repository file for it to 293 * work at all. 2. There is no other way to match a given foreign-key 294 * reference to its corresponding primary-key on the opposing side of 295 * the relationship. Yes, this is a crummy way to do it, but OJB doesnt 296 * provide explicit matches of foreign-keys to primary keys, and always 297 * assumes that foreign-keys map to primary keys on the other object, 298 * and never to a set of candidate keys, or any other column. 299 */ 300 301 @Override 302 public Map getForeignKeysForReference(Class clazz, String attributeName) { 303 // yelp if nulls were passed in 304 if (clazz == null) { 305 throw new IllegalArgumentException("The Class passed in for the clazz argument was null."); 306 } 307 if (attributeName == null) { 308 throw new IllegalArgumentException("The String passed in for the attributeName argument was null."); 309 } 310 311 // get the class of the attribute name 312 Class attributeClass = getBusinessObjectAttributeClass(clazz, attributeName); 313 if (attributeClass == null) { 314 throw new ReferenceAttributeDoesntExistException("Requested attribute: '" + attributeName + "' does not exist " + "on class: '" + clazz.getName() + "'."); 315 } 316 317 // make sure the class of the attribute descends from BusinessObject, 318 // otherwise throw an exception 319 if ((!PersistableBusinessObject.class.isAssignableFrom(attributeClass)) && 320 (!PersistableBusinessObjectBaseAdapter.class.isAssignableFrom(attributeClass))) { 321 throw new ObjectNotABusinessObjectRuntimeException("Attribute requested (" + attributeName + 322 ") is of class: " + "'" + attributeClass.getName() + "' and is not a " + 323 "descendent of BusinessObject. Only descendents of BusinessObject " + "can be used."); 324 } 325 326 Map fkMap = new HashMap(); 327 328 // make sure the attribute designated is listed as a 329 // reference-descriptor on the clazz specified, otherwise 330 // throw an exception (OJB); 331 ClassDescriptor classDescriptor = getClassDescriptor(clazz); 332 ObjectReferenceDescriptor referenceDescriptor = classDescriptor.getObjectReferenceDescriptorByName(attributeName); 333 if (referenceDescriptor == null) { 334 throw new ReferenceAttributeNotAnOjbReferenceException("Attribute requested (" + attributeName + ") is not listed " + "in OJB as a reference-descriptor for class: '" + clazz.getName() + "'"); 335 } 336 337 // special case when the attributeClass passed in doesnt match the 338 // class of the reference-descriptor as defined in ojb-repository. 339 // Currently 340 // the only case of this happening is ObjectCode vs. 341 // ObjectCodeCurrent. 342 if (!attributeClass.equals(referenceDescriptor.getItemClass())) { 343 344 if (referenceConversionMap.containsKey(attributeClass)) { 345 attributeClass = referenceConversionMap.get(attributeClass); 346 } else { 347 throw new RuntimeException("The Class of the Java member [" + attributeClass.getName() + "] '" + attributeName + "' does not match the class of the " + "reference-descriptor [" + referenceDescriptor.getItemClass().getName() + "]. " + "This is an unhandled special case for which special code needs to be written " + "in this class."); 348 } 349 } 350 351 // get the list of the foreign-keys for this reference-descriptor 352 // (OJB) 353 Vector fkFields = referenceDescriptor.getForeignKeyFields(); 354 Iterator fkIterator = fkFields.iterator(); 355 356 // get the list of the corresponding pk fields on the other side of 357 // the relationship 358 List pkFields = getPrimaryKeys(attributeClass); 359 Iterator pkIterator = pkFields.iterator(); 360 361 // make sure the size of the pkIterator is the same as the 362 // size of the fkIterator, otherwise this whole thing is borked 363 if (pkFields.size() != fkFields.size()) { 364 throw new RuntimeException("KualiPersistenceStructureService Error: The number of " + "foreign keys doesnt match the number of primary keys. This may be a " + "result of misconfigured OJB-repository files."); 365 } 366 367 // walk through the list of the foreign keys, get their types 368 while (fkIterator.hasNext()) { 369 // if there is a next FK but not a next PK, then we've got a big 370 // problem, 371 // and cannot continue 372 if (!pkIterator.hasNext()) { 373 throw new RuntimeException("The number of foriegn keys dont match the number of primary " + "keys for the reference '" + attributeName + "', on BO of type '" + clazz.getName() + "'. " + "This should never happen under normal circumstances, as it means that the OJB repository " + "files are misconfigured."); 374 } 375 376 // get the field name of the fk & pk field 377 String fkFieldName = (String) fkIterator.next(); 378 String pkFieldName = (String) pkIterator.next(); 379 380 // add the fieldName and fieldType to the map 381 fkMap.put(fkFieldName, pkFieldName); 382 } 383 384 return fkMap; 385 } 386 387 388 @Override 389 public Map<String, String> getInverseForeignKeysForCollection(Class boClass, String collectionName) { 390 // yelp if nulls were passed in 391 if (boClass == null) { 392 throw new IllegalArgumentException("The Class passed in for the boClass argument was null."); 393 } 394 if (collectionName == null) { 395 throw new IllegalArgumentException("The String passed in for the attributeName argument was null."); 396 } 397 398 PropertyDescriptor propertyDescriptor = null; 399 400 // make an instance of the class passed 401 Object classInstance; 402 try { 403 classInstance = boClass.newInstance(); 404 } catch (Exception e) { 405 throw new RuntimeException(e); 406 } 407 408 // make sure the attribute exists at all, throw exception if not 409 try { 410 propertyDescriptor = PropertyUtils.getPropertyDescriptor(classInstance, collectionName); 411 } catch (Exception e) { 412 throw new RuntimeException(e); 413 } 414 if (propertyDescriptor == null) { 415 throw new ReferenceAttributeDoesntExistException("Requested attribute: '" + collectionName + "' does not exist " + "on class: '" + boClass.getName() + "'. GFK"); 416 } 417 418 // get the class of the attribute name 419 Class attributeClass = propertyDescriptor.getPropertyType(); 420 421 // make sure the class of the attribute descends from BusinessObject, 422 // otherwise throw an exception 423 if (!Collection.class.isAssignableFrom(attributeClass)) { 424 throw new ObjectNotABusinessObjectRuntimeException("Attribute requested (" + collectionName + ") is of class: " + "'" + attributeClass.getName() + "' and is not a " + "descendent of Collection"); 425 } 426 427 // make sure the collection designated is listed as a 428 // collection-descriptor 429 // on the boClass specified, otherwise throw an exception 430 ClassDescriptor classDescriptor = getClassDescriptor(boClass); 431 CollectionDescriptor collectionDescriptor = classDescriptor.getCollectionDescriptorByName(collectionName); 432 433 // in collections, the number of keys is equal to the number of keys in 434 // the parent class (the class with the collection). 435 // Each of the primary keys on the parent object will be mapped to a 436 // field in the element object. 437 438 List parentForeignKeys = getPrimaryKeys(boClass); 439 Vector childPrimaryKeysLegacy = collectionDescriptor.getForeignKeyFields(); 440 441 if (parentForeignKeys.size() != childPrimaryKeysLegacy.size()) { 442 throw new RuntimeException("The number of keys in the class descriptor and the inverse foreign key mapping for the collection descriptors do not match."); 443 } 444 445 Map<String, String> fkToPkMap = new HashMap<String, String>(); 446 447 Iterator pFKIter = parentForeignKeys.iterator(); 448 Iterator cPKIterator = childPrimaryKeysLegacy.iterator(); 449 450 while (pFKIter.hasNext()) { 451 String parentForeignKey = (String) pFKIter.next(); 452 String childPrimaryKey = (String) cPKIterator.next(); 453 454 fkToPkMap.put(parentForeignKey, childPrimaryKey); 455 } 456 457 return fkToPkMap; 458 } 459 460 /** 461 * @see org.kuali.rice.krad.service.PersistenceService#getNestedForeignKeyMap(java.lang.Class) 462 */ 463 464 @Override 465 public Map getNestedForeignKeyMap(Class persistableObjectClass) { 466 Map fkMap = new HashMap(); 467 ClassDescriptor classDescriptor = getClassDescriptor(persistableObjectClass); 468 Vector objectReferences = classDescriptor.getObjectReferenceDescriptors(); 469 for (Iterator iter = objectReferences.iterator(); iter.hasNext();) { 470 ObjectReferenceDescriptor objectReferenceDescriptor = (ObjectReferenceDescriptor) iter.next(); 471 ClassDescriptor referenceDescriptor = this.getClassDescriptor(objectReferenceDescriptor.getItemClass()); 472 473 FieldDescriptor[] fkFields = objectReferenceDescriptor.getForeignKeyFieldDescriptors(classDescriptor); 474 FieldDescriptor[] pkFields = referenceDescriptor.getPkFields(); 475 for (int i = 0; i < pkFields.length; i++) { 476 FieldDescriptor pkField = pkFields[i]; 477 fkMap.put(objectReferenceDescriptor.getAttributeName() + "." + pkField.getAttributeName(), fkFields[i].getAttributeName()); 478 } 479 } 480 481 return fkMap; 482 } 483 484 /** 485 * @see org.kuali.rice.krad.service.PersistenceMetadataService#hasPrimaryKeyFieldValues(java.lang.Object) 486 */ 487 @Override 488 public boolean hasPrimaryKeyFieldValues(Object persistableObject) { 489 Map keyFields = getPrimaryKeyFieldValues(persistableObject); 490 491 boolean emptyField = false; 492 for (Iterator i = keyFields.entrySet().iterator(); !emptyField && i.hasNext();) { 493 Map.Entry e = (Map.Entry) i.next(); 494 495 Object fieldValue = e.getValue(); 496 if (fieldValue == null) { 497 emptyField = true; 498 } else if (fieldValue instanceof String) { 499 if (StringUtils.isEmpty((String) fieldValue)) { 500 emptyField = true; 501 } else { 502 emptyField = false; 503 } 504 } 505 } 506 507 return !emptyField; 508 } 509 510 /** 511 * @see org.kuali.rice.krad.service.PersistenceService#getForeignKeyFieldsPopulationState(org.kuali.rice.krad.bo.BusinessObject, 512 * java.lang.String) 513 */ 514 @Override 515 public ForeignKeyFieldsPopulationState getForeignKeyFieldsPopulationState(PersistableBusinessObject bo, String referenceName) { 516 boolean allFieldsPopulated = true; 517 boolean anyFieldsPopulated = false; 518 List<String> unpopulatedFields = new ArrayList<String>(); 519 520 // yelp if nulls were passed in 521 if (bo == null) { 522 throw new IllegalArgumentException("The Class passed in for the BusinessObject argument was null."); 523 } 524 if (StringUtils.isBlank(referenceName)) { 525 throw new IllegalArgumentException("The String passed in for the referenceName argument was null or empty."); 526 } 527 528 PropertyDescriptor propertyDescriptor = null; 529 530 // make sure the attribute exists at all, throw exception if not 531 try { 532 propertyDescriptor = PropertyUtils.getPropertyDescriptor(bo, referenceName); 533 } catch (Exception e) { 534 throw new RuntimeException(e); 535 } 536 if (propertyDescriptor == null) { 537 throw new ReferenceAttributeDoesntExistException("Requested attribute: '" + referenceName + "' does not exist " + "on class: '" + bo.getClass().getName() + "'."); 538 } 539 540 // get the class of the attribute name 541 Class referenceClass = propertyDescriptor.getPropertyType(); 542 543 // make sure the class of the attribute descends from BusinessObject, 544 // otherwise throw an exception 545 if (!PersistableBusinessObject.class.isAssignableFrom(referenceClass)) { 546 throw new ObjectNotABusinessObjectRuntimeException("Attribute requested (" + referenceName + ") is of class: " + "'" + referenceClass.getName() + "' and is not a " + "descendent of BusinessObject. Only descendents of BusinessObject " + "can be used."); 547 } 548 549 // make sure the attribute designated is listed as a 550 // reference-descriptor 551 // on the clazz specified, otherwise throw an exception (OJB); 552 553 ClassDescriptor classDescriptor = getClassDescriptor(bo.getClass()); 554 555 // This block is a combination of legacy and jpa 556 ObjectReferenceDescriptor referenceDescriptor = classDescriptor.getObjectReferenceDescriptorByName(referenceName); 557 if (referenceDescriptor == null) { 558 throw new ReferenceAttributeNotAnOjbReferenceException("Attribute requested (" + referenceName + ") is not listed " + "in OJB as a reference-descriptor for class: '" + bo.getClass().getName() + "'"); 559 } 560 561 // get the list of the foreign-keys for this reference-descriptor 562 Vector fkFieldsLegacy = referenceDescriptor.getForeignKeyFields(); 563 Iterator fkIteratorLegacy = fkFieldsLegacy.iterator(); 564 565 // walk through the list of the foreign keys, get their types 566 while (fkIteratorLegacy.hasNext()) { 567 568 // get the field name of the fk & pk field 569 String fkFieldName = (String) fkIteratorLegacy.next(); 570 571 // get the value for the fk field 572 Object fkFieldValue = null; 573 try { 574 fkFieldValue = PropertyUtils.getSimpleProperty(bo, fkFieldName); 575 } 576 577 // abort if the value is not retrievable 578 catch (Exception e) { 579 throw new RuntimeException(e); 580 } 581 582 // test the value 583 if (fkFieldValue == null) { 584 allFieldsPopulated = false; 585 unpopulatedFields.add(fkFieldName); 586 } else if (fkFieldValue instanceof String) { 587 if (StringUtils.isBlank((String) fkFieldValue)) { 588 allFieldsPopulated = false; 589 unpopulatedFields.add(fkFieldName); 590 } else { 591 anyFieldsPopulated = true; 592 } 593 } else { 594 anyFieldsPopulated = true; 595 } 596 } 597 598 // sanity check. if the flag for all fields populated is set, then 599 // there should be nothing in the unpopulatedFields list 600 if (allFieldsPopulated) { 601 if (!unpopulatedFields.isEmpty()) { 602 throw new RuntimeException("The flag is set that indicates all fields are populated, but there " + "are fields present in the unpopulatedFields list. This should never happen, and indicates " + "that the logic in this method is broken."); 603 } 604 } 605 606 return new ForeignKeyFieldsPopulationState(allFieldsPopulated, anyFieldsPopulated, unpopulatedFields); 607 } 608 609 /** 610 * @see org.kuali.rice.krad.service.PersistenceStructureService#listReferenceObjectFieldNames(java.lang.Class) 611 */ 612 613 @Override 614 public Map<String, Class> listReferenceObjectFields(Class boClass) { 615 // validate parameter 616 if (boClass == null) { 617 throw new IllegalArgumentException("Class specified in the parameter was null."); 618 } 619 620 Map<String, Class> references = new HashMap<String, Class>(); 621 ClassDescriptor classDescriptor = getClassDescriptor(boClass); 622 Collection<ObjectReferenceDescriptor> referenceDescriptors = classDescriptor.getObjectReferenceDescriptors(true); 623 624 for (ObjectReferenceDescriptor referenceDescriptor : referenceDescriptors) { 625 /* 626 * Below check is performed for OJB specific inheritance implementation. For more information see the OJB 627 * documentation: http://db.apache.org/ojb/docu/guides/advanced-technique.html#table-per-subclass 628 */ 629 String superReferenceDescriptor = referenceDescriptor.getAttributeName(); 630 if (!SuperReferenceDescriptor.SUPER_FIELD_INTERNAL_NAME.equals(superReferenceDescriptor)) { 631 references.put(superReferenceDescriptor, referenceDescriptor.getItemClass()); 632 } 633 } 634 635 return references; 636 } 637 638 639 @Override 640 public Map<String, Class> listCollectionObjectTypes(Class boClass) { 641 if (boClass == null) { 642 throw new IllegalArgumentException("Class specified in the parameter was null."); 643 } 644 645 Map<String, Class> references = new HashMap<String, Class>(); 646 ClassDescriptor classDescriptor = null; 647 try { 648 classDescriptor = getClassDescriptor(boClass); 649 } catch (ClassNotPersistableException cnpe) { 650 return references; 651 } 652 653 Collection<CollectionDescriptor> collectionDescriptors = classDescriptor.getCollectionDescriptors(true); 654 for (CollectionDescriptor collectionDescriptor : collectionDescriptors) { 655 references.put(collectionDescriptor.getAttributeName(), collectionDescriptor.getItemClass()); 656 } 657 658 return references; 659 } 660 661 @Override 662 public Map<String, Class> listCollectionObjectTypes(PersistableBusinessObject bo) { 663 // validate parameter 664 if (bo == null) { 665 throw new IllegalArgumentException("BO specified in the parameter was null."); 666 } 667 if (!(bo instanceof PersistableBusinessObject)) { 668 throw new IllegalArgumentException("BO specified [" + bo.getClass().getName() + "] must be a class that " + "inherits from BusinessObject."); 669 } 670 671 return listCollectionObjectTypes(bo.getClass()); 672 } 673 674 /** 675 * @see org.kuali.rice.krad.service.PersistenceStructureService#listReferenceObjectFieldNames(org.kuali.rice.krad.bo.BusinessObject) 676 */ 677 @Override 678 public Map<String, Class> listReferenceObjectFields(PersistableBusinessObject bo) { 679 // validate parameter 680 if (bo == null) { 681 throw new IllegalArgumentException("BO specified in the parameter was null."); 682 } 683 684 return listReferenceObjectFields(bo.getClass()); 685 } 686 687 688 @Override 689 public boolean isReferenceUpdatable(Class boClass, String referenceName) { 690 ClassDescriptor classDescriptor = getClassDescriptor(boClass); 691 ObjectReferenceDescriptor refDesc = classDescriptor.getObjectReferenceDescriptorByName(referenceName); 692 return refDesc.getCascadingStore() != ObjectReferenceDescriptor.CASCADE_NONE; 693 } 694 695 696 @Override 697 public boolean isCollectionUpdatable(Class boClass, String collectionName) { 698 ClassDescriptor cd = getClassDescriptor(boClass); 699 CollectionDescriptor collDesc = cd.getCollectionDescriptorByName(collectionName); 700 return collDesc.getCascadingStore() != ObjectReferenceDescriptor.CASCADE_NONE; 701 } 702 703 704 @Override 705 public boolean hasCollection(Class boClass, String collectionName) { 706 ClassDescriptor cd = getClassDescriptor(boClass); 707 return cd.getCollectionDescriptorByName(collectionName) != null; 708 } 709 710 711 @Override 712 public boolean hasReference(Class boClass, String referenceName) { 713 ClassDescriptor cd = getClassDescriptor(boClass); 714 return cd.getObjectReferenceDescriptorByName(referenceName) != null; 715 } 716 717 /** 718 * This overridden method ... 719 * 720 * @see org.kuali.rice.krad.service.PersistenceStructureService#getTableName(java.lang.Class) 721 */ 722 723 @Override 724 public String getTableName(Class<? extends PersistableBusinessObject> boClass) { 725 ClassDescriptor cd = getClassDescriptor(boClass); 726 return cd.getFullTableName(); 727 } 728 729 730} 731