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