Coverage Report - org.kuali.rice.kns.dao.impl.PersistenceDaoJpa
 
Classes in this File Line Coverage Branch Coverage Complexity
PersistenceDaoJpa
0%
0/101
0%
0/38
2.529
 
 1  
 /*
 2  
  * Copyright 2007-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.kns.dao.impl;
 17  
 
 18  
 import java.lang.reflect.Field;
 19  
 import java.util.Collection;
 20  
 import java.util.HashMap;
 21  
 import java.util.List;
 22  
 import java.util.Map;
 23  
 
 24  
 import javax.persistence.EntityManager;
 25  
 import javax.persistence.EntityNotFoundException;
 26  
 import javax.persistence.PersistenceContext;
 27  
 
 28  
 import org.apache.commons.lang.StringUtils;
 29  
 import org.hibernate.proxy.HibernateProxy;
 30  
 import org.kuali.rice.core.framework.persistence.jpa.metadata.CollectionDescriptor;
 31  
 import org.kuali.rice.core.framework.persistence.jpa.metadata.EntityDescriptor;
 32  
 import org.kuali.rice.core.framework.persistence.jpa.metadata.JoinColumnDescriptor;
 33  
 import org.kuali.rice.core.framework.persistence.jpa.metadata.MetadataManager;
 34  
 import org.kuali.rice.core.framework.persistence.jpa.metadata.ObjectDescriptor;
 35  
 import org.kuali.rice.kns.dao.PersistenceDao;
 36  
 import org.kuali.rice.kns.service.KNSServiceLocator;
 37  
 
 38  0
 public class PersistenceDaoJpa implements PersistenceDao {
 39  0
         static org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory.getLog(PersistenceDaoJpa.class);
 40  
         
 41  
         @PersistenceContext
 42  
         private EntityManager entityManager;
 43  
     
 44  
         /**
 45  
          * @see org.kuali.rice.kns.dao.PersistenceDao#clearCache()
 46  
          */
 47  0
         public void clearCache() {}
 48  
 
 49  
         /**
 50  
          * @see org.kuali.rice.kns.dao.PersistenceDao#resolveProxy(java.lang.Object)
 51  
          */
 52  
         public Object resolveProxy(Object o) {
 53  0
                 if (o instanceof HibernateProxy) {
 54  
                 try {
 55  0
                         final Object realObject = ((HibernateProxy) o).getHibernateLazyInitializer().getImplementation();
 56  0
                         return realObject;
 57  0
                 } catch (EntityNotFoundException enfe) {
 58  0
                         return null;
 59  
                 }
 60  
         }
 61  0
                 return o;
 62  
         }
 63  
 
 64  
         /**
 65  
          * @see org.kuali.rice.kns.dao.PersistenceDao#retrieveAllReferences(java.lang.Object)
 66  
          */
 67  
         public void retrieveAllReferences(Object o) {
 68  0
                 EntityDescriptor ed = MetadataManager.getEntityDescriptor(o.getClass());
 69  0
                 for (ObjectDescriptor od : ed.getObjectRelationships()) {
 70  0
                         retrieveReference(o, od.getAttributeName());
 71  
                 }
 72  0
                 for (CollectionDescriptor cd : ed.getCollectionRelationships()) {
 73  0
                         retrieveReference(o, cd.getAttributeName());
 74  
                 }
 75  0
         }
 76  
 
 77  
         /**
 78  
          * @see org.kuali.rice.kns.dao.PersistenceDao#retrieveReference(java.lang.Object, java.lang.String)
 79  
          */
 80  
         public void retrieveReference(Object o, String referenceName) {
 81  
                 try {
 82  0
                         if (getEntityManager().contains(o)) {
 83  0
                                 LOG.debug("the entity manager contains the object");
 84  
                         }
 85  
                         
 86  0
                         Field field = getField(o.getClass(), referenceName);
 87  0
                         field.setAccessible(true);
 88  
                         
 89  0
                         String fk = null;
 90  0
                         String foreignPK = null;
 91  
                         
 92  0
                         if (isReferenceCollection(o, referenceName)) {
 93  0
                                 Collection reference = retrieveCollectionReference(o, referenceName);
 94  0
                                 field.set(o, reference);
 95  0
                         } else {
 96  0
                                 Object reference = retrieveObjectReference(o, referenceName);
 97  0
                                 field.set(o, reference);
 98  
                         }
 99  0
                 } catch (Exception e) {
 100  0
                         e.printStackTrace();
 101  0
                 }                
 102  0
         }
 103  
         
 104  
         private Field getField(Class clazz, String name) throws NoSuchFieldException {
 105  0
                 if (clazz.equals(Object.class)) {
 106  0
                         throw new NoSuchFieldException(name);
 107  
                 }
 108  0
                 Field field = null;
 109  
                 try {
 110  0
                         field = clazz.getDeclaredField(name);
 111  0
                 } catch (Exception e) {}
 112  0
                 if (field == null) {
 113  0
                         field = getField(clazz.getSuperclass(), name);
 114  
                 }
 115  0
                 return field;
 116  
         }
 117  
         
 118  
         /**
 119  
          * Determines if the reference on the given object represents a collection or not
 120  
          * 
 121  
          * @param o the object which is to be refreshed
 122  
          * @param referenceName the name of the reference to refresh
 123  
          * @return true if the reference is a collection, false otherwise
 124  
          */
 125  
         protected boolean isReferenceCollection(Object o, String referenceName) {
 126  0
                 EntityDescriptor ed = MetadataManager.getEntityDescriptor(o.getClass());
 127  0
                 return ed.getCollectionDescriptorByName(referenceName) != null;
 128  
         }
 129  
         
 130  
         /**
 131  
          * This method fetches a collection to refresh a reference
 132  
          * 
 133  
          * @param o the object to refresh
 134  
          * @param referenceName the name of the reference to refresh
 135  
          * @return the retrieved object to refresh the 
 136  
          * @throws NoSuchFieldException 
 137  
          * @throws IllegalAccessException 
 138  
          * @throws IllegalArgumentException 
 139  
          */
 140  
         protected Collection retrieveCollectionReference(Object o, String referenceName) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
 141  0
                 final EntityDescriptor ed = MetadataManager.getEntityDescriptor(o.getClass());
 142  0
                 final CollectionDescriptor cd = ed.getCollectionDescriptorByName(referenceName);
 143  0
                 final EntityDescriptor foreignEntityDescriptor = MetadataManager.getEntityDescriptor(cd.getTargetEntity());
 144  
                 
 145  0
                 Map<String, Object> searchKey = new HashMap<String, Object>();
 146  0
                 for (String foreignKey : cd.getForeignKeyFields()) {
 147  0
                         Field localField = getField(o.getClass(), foreignKey);
 148  0
                         localField.setAccessible(true);
 149  0
                         final Object localValue = localField.get(o);
 150  
                         
 151  0
                         final String foreignKeyProperty = getForeignKeyPropertyForKeyWithPossibleInverse(foreignKey, ed, foreignEntityDescriptor, cd);
 152  
 
 153  0
                         searchKey.put(foreignKeyProperty, localValue);
 154  0
                 }
 155  0
                 return KNSServiceLocator.getBusinessObjectService().findMatching(cd.getTargetEntity(), searchKey);
 156  
         }
 157  
         
 158  
         /**
 159  
          * Finds the correct foreign key property which corresponds to the given key
 160  
          * 
 161  
          * @param foreignKey the name of the key we want to find the proper foreign name for
 162  
          * @param localEntityDescriptor the descriptor of the entity that key is on
 163  
          * @param foreignEntityDescriptor the descriptor of the entity we're trying to retrieve
 164  
          * @param joinColumnDescriptors a Map of the JoinColumnDescriptors that describe the relationship from the local entity's point of view, keyed by the column name of the JoinColumnDescriptor 
 165  
          * @return the name of the property on the related object
 166  
          */
 167  
         protected String getForeignKeyPropertyForKeyWithPossibleInverse(String foreignKey, EntityDescriptor localEntityDescriptor, EntityDescriptor foreignEntityDescriptor, CollectionDescriptor collectionDescriptor) {
 168  0
                 final String foreignKeyColumn = localEntityDescriptor.getFieldByName(foreignKey).getColumn();
 169  
                 
 170  0
                 int count = 0;
 171  0
                 JoinColumnDescriptor joinColumnDescriptor = null;
 172  0
                 JoinColumnDescriptor inverseColumnDescriptor = null;
 173  0
                 while (count < collectionDescriptor.getJoinColumnDescriptors().size() && joinColumnDescriptor == null) {
 174  0
                         if (collectionDescriptor.getJoinColumnDescriptors().get(count).getName().equalsIgnoreCase(foreignKeyColumn)) {
 175  0
                                 joinColumnDescriptor = collectionDescriptor.getJoinColumnDescriptors().get(count);
 176  0
                                 if (count < collectionDescriptor.getInverseJoinColumnDescriptors().size()) {
 177  0
                                         inverseColumnDescriptor = collectionDescriptor.getInverseJoinColumnDescriptors().get(count);
 178  
                                 }
 179  
                         }
 180  0
                         count += 1;
 181  
                 }
 182  
                 
 183  0
                 if (inverseColumnDescriptor != null) {
 184  0
                         return foreignEntityDescriptor.getFieldByColumnName(inverseColumnDescriptor.getName()).getName();
 185  
                 }
 186  
                 
 187  0
                 if (!StringUtils.isBlank(joinColumnDescriptor.getReferencedColumName())) {
 188  0
                         return foreignEntityDescriptor.getFieldByColumnName(joinColumnDescriptor.getReferencedColumName()).getName();
 189  
                 }
 190  
 
 191  0
                 return foreignEntityDescriptor.getFieldByColumnName(joinColumnDescriptor.getName()).getName();
 192  
 
 193  
         }
 194  
         
 195  
         /**
 196  
          * Fetches an object reference
 197  
          * 
 198  
          * @param o the object to refresh
 199  
          * @param referenceName the name of the reference to fetch
 200  
          * @return the fetched referred to object
 201  
          * @throws IllegalAccessException 
 202  
          * @throws IllegalArgumentException 
 203  
          * @throws NoSuchFieldException 
 204  
          * @throws ClassNotFoundException 
 205  
          * @throws InstantiationException 
 206  
          */
 207  
         protected Object retrieveObjectReference(Object o, String referenceName) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InstantiationException, ClassNotFoundException {
 208  0
                 final EntityDescriptor ed = MetadataManager.getEntityDescriptor(o.getClass());
 209  0
                 final ObjectDescriptor od = ed.getObjectDescriptorByName(referenceName);
 210  
                 
 211  0
                 final Object foreignKeyObject = buildForeignKeyObject(o, ed, od);
 212  0
                 return getEntityManager().find(od.getTargetEntity(), foreignKeyObject);
 213  
         }
 214  
         
 215  
         /**
 216  
          * Builds a foreign key object for the relationship given by the foreignKeyClass and the objectDescriptor
 217  
          * 
 218  
          * @param o the object to refresh
 219  
          * @param localEntityDescriptor the entity descriptor for that object
 220  
          * @param objectDescriptor the object descriptor for the relationship to refresh
 221  
          * @return the foreign key to fetch that object
 222  
          * @throws IllegalArgumentException
 223  
          * @throws NoSuchFieldException
 224  
          * @throws IllegalAccessException
 225  
          * @throws InstantiationException 
 226  
          */
 227  
         protected Object buildForeignKeyObject(Object o, EntityDescriptor localEntityDescriptor, ObjectDescriptor objectDescriptor) throws IllegalArgumentException, NoSuchFieldException, IllegalAccessException, InstantiationException {
 228  0
                 return (objectDescriptor.getForeignKeyFields().size() == 1) ? 
 229  
                                         buildSingleKeyForeignKeyObject(o, objectDescriptor.getForeignKeyFields().get(0)) : 
 230  
                                         buildCompositeForeignKeyObject(o, localEntityDescriptor, objectDescriptor);
 231  
         }
 232  
 
 233  
         /**
 234  
          * Builds a composite key to fetch a reference
 235  
          * 
 236  
          * @param o the object to refresh
 237  
          * @param localEntityDescriptor the entity descriptor for that object
 238  
          * @param objectDescriptor the object descriptor for the relationship to refresh
 239  
          * @return the foreign key to fetch that object
 240  
          * @throws InstantiationException
 241  
          * @throws IllegalAccessException
 242  
          * @throws NoSuchFieldException
 243  
          */
 244  
         private Object buildCompositeForeignKeyObject(Object o, EntityDescriptor localEntityDescriptor, ObjectDescriptor objectDescriptor) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
 245  0
                 final Map<String, JoinColumnDescriptor> joinColumnDescriptors = buildJoinColumnDescriptorMap(objectDescriptor.getJoinColumnDescriptors());
 246  
                 
 247  0
                 final EntityDescriptor foreignEntityDescriptor = MetadataManager.getEntityDescriptor(objectDescriptor.getTargetEntity());
 248  0
                 final Class foreignEntityIdClass = foreignEntityDescriptor.getIdClass();
 249  
                 
 250  0
                 Object foreignEntityId = foreignEntityIdClass.newInstance();
 251  0
                 for (String foreignKey : objectDescriptor.getForeignKeyFields()) {
 252  
                         // get the value from the current object
 253  0
                         Field localField = getField(o.getClass(), foreignKey);
 254  0
                         localField.setAccessible(true);
 255  0
                         final Object localValue = localField.get(o); 
 256  
                         
 257  0
                         final String foreignKeyProperty = getForeignKeyPropertyForKey(foreignKey, localEntityDescriptor, foreignEntityDescriptor, joinColumnDescriptors);
 258  
                                                 
 259  0
                         Field foreignField = getField(foreignEntityId.getClass(), foreignKeyProperty);
 260  0
                         foreignField.setAccessible(true);
 261  0
                         foreignField.set(foreignEntityId, localValue);
 262  0
                 }
 263  0
                 return foreignEntityId;
 264  
         }
 265  
         
 266  
         /**
 267  
          * Finds the correct foreign key property which corresponds to the given key
 268  
          * 
 269  
          * @param foreignKey the name of the key we want to find the proper foreign name for
 270  
          * @param localEntityDescriptor the descriptor of the entity that key is on
 271  
          * @param foreignEntityDescriptor the descriptor of the entity we're trying to retrieve
 272  
          * @param joinColumnDescriptors a Map of the JoinColumnDescriptors that describe the relationship from the local entity's point of view, keyed by the column name of the JoinColumnDescriptor 
 273  
          * @return the name of the property on the related object
 274  
          */
 275  
         protected String getForeignKeyPropertyForKey(String foreignKey, EntityDescriptor localEntityDescriptor, EntityDescriptor foreignEntityDescriptor, Map<String, JoinColumnDescriptor> joinColumnDescriptors) {
 276  0
                 final String foreignKeyColumn = localEntityDescriptor.getFieldByName(foreignKey).getColumn();
 277  0
                 final JoinColumnDescriptor joinColumnDescriptor = joinColumnDescriptors.get(foreignKeyColumn);
 278  
                 
 279  0
                 return (!StringUtils.isBlank(joinColumnDescriptor.getReferencedColumName())) ? 
 280  
                                 foreignEntityDescriptor.getFieldByColumnName(joinColumnDescriptor.getReferencedColumName()).getName() : 
 281  
                                 foreignEntityDescriptor.getFieldByColumnName(joinColumnDescriptor.getName()).getName();
 282  
 
 283  
         }
 284  
         
 285  
         /**
 286  
          * Turns a List of JoinColumnDescriptors and maps them by their name
 287  
          * 
 288  
          * @param joinColumnDescriptors a List of JoinColumnDescriptors
 289  
          * @return a Map the List as a Map, keyed by the name of the JoinColumn
 290  
          */
 291  
         protected Map<String, JoinColumnDescriptor> buildJoinColumnDescriptorMap(List<JoinColumnDescriptor> joinColumnDescriptors) {
 292  0
                 Map<String, JoinColumnDescriptor> descriptorMap = new HashMap<String, JoinColumnDescriptor>();
 293  0
                 for (JoinColumnDescriptor joinColumnDescriptor : joinColumnDescriptors) {
 294  0
                         descriptorMap.put(joinColumnDescriptor.getName(), joinColumnDescriptor);
 295  
                 }
 296  0
                 return descriptorMap;
 297  
         }
 298  
         
 299  
         /**
 300  
          * Builds a foreign key, where that foreign key has a single field
 301  
          * 
 302  
          * @param o the object to get the foreign key value from
 303  
          * @param singleForeignKeyFieldName the name of the foreign key field
 304  
          * @return a value for the foreign key
 305  
          * @throws NoSuchFieldException
 306  
          * @throws IllegalArgumentException
 307  
          * @throws IllegalAccessException
 308  
          */
 309  
         protected Object buildSingleKeyForeignKeyObject(Object o, String singleForeignKeyFieldName) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
 310  0
                 Field singleFKField = getField(o.getClass(), singleForeignKeyFieldName);
 311  0
                 singleFKField.setAccessible(true);
 312  0
                 return singleFKField.get(o);
 313  
         }
 314  
 
 315  
         /**
 316  
          * True if object is an instance of HibernateProxy, false otherwise
 317  
          * 
 318  
          * @see org.kuali.rice.kns.dao.PersistenceDao#isProxied(java.lang.Object)
 319  
          */
 320  
         public boolean isProxied(Object object) {
 321  0
                 return (object instanceof HibernateProxy);
 322  
         }
 323  
 
 324  
         /**
 325  
          * @return the entityManager
 326  
          */
 327  
         public EntityManager getEntityManager() {
 328  0
                 return this.entityManager;
 329  
         }
 330  
 
 331  
         /**
 332  
          * @param entityManager the entityManager to set
 333  
          */
 334  
         public void setEntityManager(EntityManager entityManager) {
 335  0
                 this.entityManager = entityManager;
 336  0
         }
 337  
 }