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