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