Coverage Report - org.kuali.rice.krad.dao.impl.BusinessObjectDaoJpa
 
Classes in this File Line Coverage Branch Coverage Complexity
BusinessObjectDaoJpa
0%
0/134
0%
0/50
2
 
 1  
 /**
 2  
  * Copyright 2005-2011 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.dao.impl;
 17  
 
 18  
 import java.util.ArrayList;
 19  
 import java.util.Collection;
 20  
 import java.util.Iterator;
 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  
 import javax.persistence.PersistenceException;
 28  
 
 29  
 import org.hibernate.FlushMode;
 30  
 import org.hibernate.Session;
 31  
 import org.hibernate.ejb.HibernateEntityManager;
 32  
 import org.hibernate.proxy.HibernateProxy;
 33  
 import org.kuali.rice.core.framework.persistence.jpa.OrmUtils;
 34  
 import org.kuali.rice.core.framework.persistence.jpa.criteria.Criteria;
 35  
 import org.kuali.rice.core.framework.persistence.jpa.criteria.QueryByCriteria;
 36  
 import org.kuali.rice.core.framework.persistence.jpa.criteria.QueryByCriteria.QueryByCriteriaType;
 37  
 import org.kuali.rice.core.framework.persistence.jpa.metadata.MetadataManager;
 38  
 import org.kuali.rice.krad.bo.BusinessObject;
 39  
 import org.kuali.rice.krad.bo.PersistableBusinessObject;
 40  
 import org.kuali.rice.krad.bo.PersistableBusinessObjectExtension;
 41  
 import org.kuali.rice.krad.dao.BusinessObjectDao;
 42  
 import org.kuali.rice.krad.service.PersistenceStructureService;
 43  
 import org.kuali.rice.krad.util.KRADPropertyConstants;
 44  
 import org.kuali.rice.krad.util.OjbCollectionHelper;
 45  
 import org.springframework.dao.DataAccessException;
 46  
 
 47  
 /**
 48  
  * This class is the JPA implementation of the BusinessObjectDao interface.
 49  
  */
 50  
 @SuppressWarnings("unchecked")
 51  
 public class BusinessObjectDaoJpa implements BusinessObjectDao {
 52  
 
 53  
         @PersistenceContext
 54  
         private EntityManager entityManager;
 55  
 
 56  
         private PersistenceStructureService persistenceStructureService;
 57  
 
 58  
         private OjbCollectionHelper ojbCollectionHelper;
 59  
 
 60  0
         public BusinessObjectDaoJpa(EntityManager entityManager, PersistenceStructureService persistenceStructureService) {
 61  0
                 this.entityManager = entityManager;
 62  0
                 this.persistenceStructureService = persistenceStructureService;
 63  0
         }
 64  
 
 65  
         /**
 66  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findBySinglePrimaryKey(java.lang.Class, java.lang.Object)
 67  
          */
 68  
         public <T extends BusinessObject> T findBySinglePrimaryKey(Class<T> clazz, Object primaryKey) {
 69  0
                 return (T) entityManager.find(clazz, primaryKey);
 70  
         }
 71  
 
 72  
         /**
 73  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findByPrimaryKey(java.lang.Class,
 74  
          *      java.util.Map)
 75  
          */
 76  
         public <T extends BusinessObject> T findByPrimaryKey(Class<T> clazz, Map<String, ?> primaryKeys) { 
 77  0
                 if (primaryKeys == null || primaryKeys.isEmpty()) {
 78  0
                         return null;
 79  
                 }
 80  0
                 T bo = null;
 81  
                 try {
 82  0
                         bo = (T) new QueryByCriteria(entityManager, buildJpaCriteria(clazz, primaryKeys)).toQuery().getSingleResult();
 83  0
                 } catch (PersistenceException e) {}
 84  0
                 return bo;
 85  
         }
 86  
         
 87  
         /**
 88  
          * Retrieves an object, based on its PK object
 89  
          * 
 90  
          * @param clazz the class of the object to retrieve
 91  
          * @param pkObject the value of the primary key
 92  
          * @return the retrieved PersistableBusinessObject
 93  
          */
 94  
         public <T extends BusinessObject> T findByPrimaryKeyUsingKeyObject(Class<T> clazz, Object pkObject) { 
 95  0
                 if (pkObject == null) {
 96  0
                         return null;
 97  
                 }
 98  0
                 T bo = null;
 99  
                 try {
 100  0
                         bo = (T) entityManager.find(clazz, pkObject);
 101  0
                 } catch (PersistenceException e) {}
 102  0
                 return bo;
 103  
         }
 104  
 
 105  
         /**
 106  
          * Retrieves all of the records for a given class name.
 107  
          * 
 108  
          * @param clazz -
 109  
          *            the name of the object being used, either KualiCodeBase or a
 110  
          *            subclass
 111  
          * @return Collection
 112  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAll(java.lang.Class)
 113  
          */
 114  
         public <T extends BusinessObject> Collection<T> findAll(Class<T> clazz) {
 115  0
                 return (Collection<T>) new QueryByCriteria(entityManager, new Criteria(clazz.getName())).toQuery().getResultList();
 116  
         }
 117  
 
 118  
         /**
 119  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllOrderBy(java.lang.Class,
 120  
          *      java.lang.String, boolean)
 121  
          */
 122  
         public <T extends BusinessObject> Collection<T> findAllOrderBy(Class<T> clazz, String sortField, boolean sortAscending) {
 123  0
                 Criteria criteria = new Criteria(clazz.getName());
 124  0
                 criteria.orderBy(sortField, sortAscending);
 125  0
                 return new QueryByCriteria(entityManager, criteria).toQuery().getResultList();
 126  
         }
 127  
 
 128  
         /**
 129  
          * This is the default impl that comes with Kuali - uses OJB.
 130  
          * 
 131  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatching(java.lang.Class,
 132  
          *      java.util.Map)
 133  
          */
 134  
         public <T extends BusinessObject> Collection<T> findMatching(Class<T> clazz, Map<String, ?> fieldValues) {
 135  0
                 return (Collection<T>)new QueryByCriteria(entityManager, buildJpaCriteria(clazz, fieldValues)).toQuery().getResultList();
 136  
         }
 137  
 
 138  
         /**
 139  
          * Uses the passed query to form a Rice QueryByCriteria, which then translates to a JPA query and retrieves results
 140  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatching(org.kuali.rice.core.framework.persistence.jpa.criteria.Criteria)
 141  
          */
 142  
         public <T extends BusinessObject> Collection<T> findMatching(Criteria criteria) {
 143  0
                 return (List<T>)new QueryByCriteria(entityManager, criteria).toQuery().getResultList();
 144  
         }
 145  
 
 146  
         /**
 147  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllActive(java.lang.Class)
 148  
          */
 149  
         public <T extends BusinessObject> Collection<T> findAllActive(Class<T> clazz) {
 150  0
                 return (Collection<T>)new QueryByCriteria(entityManager, buildActiveJpaCriteria(clazz)).toQuery().getResultList();
 151  
         }
 152  
 
 153  
         /**
 154  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllActive(java.lang.Class)
 155  
          */
 156  
         public <T extends BusinessObject> Collection<T> findAllInactive(Class<T> clazz) {
 157  0
                 return (Collection<T>)new QueryByCriteria(entityManager, buildInactiveJpaCriteria(clazz)).toQuery().getResultList();
 158  
         }
 159  
         
 160  
         /**
 161  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllActiveOrderBy(java.lang.Class,
 162  
          *      java.lang.String, boolean)
 163  
          */
 164  
         public <T extends BusinessObject> Collection<T> findAllActiveOrderBy(Class<T> clazz, String sortField, boolean sortAscending) {
 165  0
                 Criteria criteria = buildActiveJpaCriteria(clazz);
 166  0
                 criteria.orderBy(sortField, sortAscending);
 167  0
                 return (Collection<T>)new QueryByCriteria(entityManager, criteria).toQuery().getResultList();
 168  
         }
 169  
 
 170  
         /**
 171  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatchingActive(java.lang.Class,
 172  
          *      java.util.Map)
 173  
          */
 174  
         public <T extends BusinessObject> Collection<T> findMatchingActive(Class<T> clazz, Map<String, ?> fieldValues) {
 175  0
                 Criteria criteria = buildJpaCriteria(clazz, fieldValues);
 176  0
                 criteria.and(buildActiveJpaCriteria(clazz));
 177  0
                 return (Collection<T>)new QueryByCriteria(entityManager, criteria).toQuery().getResultList();
 178  
         }
 179  
 
 180  
         /**
 181  
          * This is the default impl that comes with Kuali - uses OJB.
 182  
          * 
 183  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#countMatching(java.lang.Class,
 184  
          *      java.util.Map)
 185  
          */
 186  
         public int countMatching(Class clazz, Map<String, ?> fieldValues) {
 187  0
                 return ((Long) new QueryByCriteria(entityManager, buildJpaCriteria(clazz, fieldValues)).toCountQuery().getSingleResult()).intValue();
 188  
         }
 189  
 
 190  
         /**
 191  
          * This is the default impl that comes with Kuali - uses OJB.
 192  
          * 
 193  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#countMatching(java.lang.Class,
 194  
          *      java.util.Map, java.util.Map)
 195  
          */
 196  
         public int countMatching(Class clazz, Map<String, ?> positiveFieldValues, Map<String, ?> negativeFieldValues) {
 197  0
                 Criteria criteria = buildJpaCriteria(clazz, positiveFieldValues);
 198  0
                 criteria.and(buildNegativeJpaCriteria(clazz, negativeFieldValues));
 199  0
                 return ((Long) new QueryByCriteria(entityManager, criteria).toCountQuery().getSingleResult()).intValue();
 200  
         }
 201  
 
 202  
         /**
 203  
          * This is the default impl that comes with Kuali - uses OJB.
 204  
          * 
 205  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatching(java.lang.Class,
 206  
          *      java.util.Map)
 207  
          */
 208  
         public <T extends BusinessObject> Collection<T> findMatchingOrderBy(Class<T> clazz, Map<String, ?> fieldValues, String sortField, boolean sortAscending) {
 209  0
                 Criteria criteria = buildJpaCriteria(clazz, fieldValues);
 210  0
                 criteria.orderBy(sortField, sortAscending);
 211  0
                 return (Collection<T>)new QueryByCriteria(entityManager, criteria).toQuery().getResultList();
 212  
         }
 213  
 
 214  
         /**
 215  
          * Saves a business object.
 216  
          * 
 217  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#save(org.kuali.rice.krad.bo.PersistableBusinessObject)
 218  
          */
 219  
         public PersistableBusinessObject save(PersistableBusinessObject bo) throws DataAccessException {
 220  
                 /* KC determined this is not needed for JPA
 221  
                 // if collections exist on the BO, create a copy and use to process the
 222  
                 // collections to ensure
 223  
                 // that removed elements are deleted from the database
 224  
                 Set<String> boCollections = getPersistenceStructureService().listCollectionObjectTypes(bo.getClass()).keySet();
 225  
                 PersistableBusinessObject savedBo = null;
 226  
                 if (!boCollections.isEmpty()) {
 227  
                         // refresh bo to get db copy of collections
 228  
                         savedBo = (PersistableBusinessObject) ObjectUtils.deepCopy(bo);
 229  
                         for (String boCollection : boCollections) {
 230  
                                 if (getPersistenceStructureService().isCollectionUpdatable(savedBo.getClass(), boCollection)) {
 231  
                                         savedBo.refreshReferenceObject(boCollection);
 232  
                                 }
 233  
                         }
 234  
                 }
 235  
                 */
 236  0
                 if (entityManager.contains(bo) && ((HibernateEntityManager)entityManager).getSession().isReadOnly(bo)) {
 237  0
                         ((HibernateEntityManager)entityManager).getSession().setReadOnly(bo, false); // are we read only?  turn that off...
 238  
                 }
 239  0
                 return reattachAndSave(bo);
 240  
         }
 241  
         
 242  
                 
 243  
 
 244  
         /**
 245  
          * Saves a business object.
 246  
          * 
 247  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#save(org.kuali.rice.krad.bo.PersistableBusinessObject)
 248  
          */
 249  
         public List<? extends PersistableBusinessObject> save(List businessObjects) throws DataAccessException {
 250  0
                 List<PersistableBusinessObject> savedBOs = new ArrayList<PersistableBusinessObject>();
 251  0
                 for (Iterator i = businessObjects.iterator(); i.hasNext();) {
 252  0
                         Object bo = i.next();
 253  0
                         final PersistableBusinessObject savedBusinessObject = reattachAndSave((PersistableBusinessObject) bo);
 254  0
                         savedBOs.add(savedBusinessObject);
 255  0
                 }
 256  0
                 return savedBOs;
 257  
         }
 258  
 
 259  
         /**
 260  
          * Deletes the business object passed in.
 261  
          * 
 262  
          * @param bo
 263  
          * @throws DataAccessException
 264  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#delete(org.kuali.rice.krad.bo.PersistableBusinessObject)
 265  
          */
 266  
         public void delete(PersistableBusinessObject bo) {
 267  0
                 final PersistableBusinessObject realPBO = materialize(bo);
 268  0
                 if (realPBO != null) {
 269  0
                         if (realPBO.getExtension() != null) {
 270  0
                                 delete(realPBO.getExtension());
 271  
                         }
 272  0
                         if (entityManager.contains(realPBO)) {
 273  0
                                 entityManager.remove(realPBO);
 274  
                         } else {
 275  0
                                 final PersistableBusinessObject foundBO = (PersistableBusinessObject)entityManager.find(realPBO.getClass(), MetadataManager.getEntityPrimaryKeyObject(realPBO));
 276  0
                                 if (foundBO != null) {
 277  0
                                         entityManager.remove(foundBO);
 278  
                                 }
 279  
                         }
 280  
                 }
 281  0
         }
 282  
         
 283  
         /**
 284  
          * If the object is a proxy, materializes it
 285  
          * 
 286  
          * @param bo the business object, which may be a sneaky proxy
 287  
          * @return the materialized non-proxied business object
 288  
          */
 289  
         protected PersistableBusinessObject materialize(PersistableBusinessObject bo) {
 290  
                 try {
 291  0
                         if (bo instanceof HibernateProxy) {
 292  0
                                 return (PersistableBusinessObject)((HibernateProxy)bo).getHibernateLazyInitializer().getImplementation();
 293  
                         }
 294  0
                         return bo;
 295  0
                 } catch (EntityNotFoundException enfe) {
 296  0
                         return null;  // could not find the entity - just return null
 297  
                 }
 298  
         }
 299  
 
 300  
         /**
 301  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#delete(java.util.List)
 302  
          */
 303  
         public void delete(List<? extends PersistableBusinessObject> boList) {
 304  0
                 for (PersistableBusinessObject bo : boList) {
 305  0
                         delete(bo);
 306  
                 }
 307  0
         }
 308  
 
 309  
         /**
 310  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#deleteMatching(java.lang.Class,
 311  
          *      java.util.Map)
 312  
          */
 313  
         public void deleteMatching(Class clazz, Map<String, ?> fieldValues) {
 314  
                 // Rice JPA MetadataManager
 315  0
                 new QueryByCriteria(entityManager, buildJpaCriteria(clazz, fieldValues), QueryByCriteriaType.DELETE).toQuery().executeUpdate();
 316  0
         }
 317  
 
 318  
         /**
 319  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#retrieve(org.kuali.rice.krad.bo.PersistableBusinessObject)
 320  
          */
 321  
         public PersistableBusinessObject retrieve(PersistableBusinessObject object) {
 322  0
                 PersistableBusinessObject pbo = null;
 323  0
                 Object pkObject = MetadataManager.getEntityPrimaryKeyObject(object);
 324  0
                 if (pkObject != null) {
 325  0
                         pbo = (PersistableBusinessObject) entityManager.find(object.getClass(), pkObject);
 326  0
                         if (pbo != null && pbo.getExtension() != null) {
 327  0
                                 pbo.setExtension((PersistableBusinessObjectExtension) entityManager.find(pbo.getExtension().getClass(), MetadataManager.getPersistableBusinessObjectPrimaryKeyObjectWithValuesForExtension(pbo, pbo.getExtension())));
 328  
                         }
 329  
                 }
 330  0
                 return pbo;
 331  
         }
 332  
 
 333  
         private Criteria buildJpaCriteria(Class clazz, Map<String, ?> fieldValues) {
 334  0
                 Criteria criteria = new Criteria(clazz.getName());
 335  0
                 for (Iterator i = fieldValues.entrySet().iterator(); i.hasNext();) {
 336  0
                         Map.Entry<String, ?> e = (Map.Entry<String, ?>) i.next();
 337  
 
 338  0
                         String key = e.getKey();
 339  0
                         Object value = e.getValue();
 340  0
                         String alias = "";
 341  0
                         String[] keySplit = key.split("\\.");
 342  0
                         if (keySplit.length > 1) {
 343  0
                                 alias = keySplit[keySplit.length-2];
 344  0
                                 String variableKey = keySplit[keySplit.length-1];
 345  0
                                 for (int j = 0; j < keySplit.length - 1; j++)  {
 346  0
                                         if (criteria.getAliasIndex(keySplit[j]) == -1) {
 347  0
                                             criteria.join(keySplit[j], keySplit[j], false, true);
 348  
                                     }
 349  
                                 }
 350  0
                                 key = "__JPA_ALIAS[['" + alias + "']]__." + variableKey;
 351  
                         }
 352  0
                         if (value == null) {
 353  0
                                 continue;
 354  0
                         } else if (value instanceof Collection) {
 355  0
                                 criteria.in(key, (Collection)value);
 356  
                         } else {
 357  0
                                 criteria.eq(key, value);
 358  
                         }
 359  0
                 }
 360  0
                 return criteria;
 361  
         }
 362  
 
 363  
         private Criteria buildActiveJpaCriteria(Class clazz) {
 364  0
                 Criteria criteria = new Criteria(clazz.getName());
 365  0
                 criteria.eq(KRADPropertyConstants.ACTIVE, true);
 366  0
                 return criteria;
 367  
         }
 368  
 
 369  
         private Criteria buildInactiveJpaCriteria(Class clazz) {
 370  0
                 Criteria criteria = new Criteria(clazz.getName());
 371  0
                 criteria.eq(KRADPropertyConstants.ACTIVE, false);
 372  0
                 return criteria;
 373  
         }
 374  
 
 375  
         private Criteria buildNegativeJpaCriteria(Class clazz, Map negativeFieldValues) {
 376  0
                 Criteria criteria = new Criteria(clazz.getName());
 377  0
                 for (Iterator i = negativeFieldValues.entrySet().iterator(); i.hasNext();) {
 378  0
                         Map.Entry e = (Map.Entry) i.next();
 379  
 
 380  0
                         String key = (String) e.getKey();
 381  0
                         Object value = e.getValue();
 382  0
                         if (value instanceof Collection) {
 383  0
                                 criteria.notIn(key, (List) value);
 384  
                         } else {
 385  0
                                 criteria.ne(key, value);
 386  
                         }
 387  0
                 }
 388  
 
 389  0
                 return criteria;
 390  
         }
 391  
 
 392  
         /**
 393  
          * @see org.kuali.rice.krad.dao.BusinessObjectDao#manageReadOnly(org.kuali.rice.krad.bo.PersistableBusinessObject)
 394  
          */
 395  
         public PersistableBusinessObject manageReadOnly(PersistableBusinessObject bo) {
 396  0
                 Session session = ((HibernateEntityManager)entityManager).getSession();
 397  0
                 FlushMode currentFlushMode = session.getFlushMode();
 398  0
                 session.setFlushMode(FlushMode.MANUAL); // make sure the merge doesn't flush what we're trying to make read only
 399  0
                 PersistableBusinessObject managedBO = entityManager.merge(bo);
 400  0
                 session.setReadOnly(managedBO, true);
 401  0
                 session.setFlushMode(currentFlushMode);
 402  0
                 return managedBO;
 403  
         }
 404  
 
 405  
         /**
 406  
          * Gets the persistenceStructureService attribute.
 407  
          * 
 408  
          * @return Returns the persistenceStructureService.
 409  
          */
 410  
         protected PersistenceStructureService getPersistenceStructureService() {
 411  0
                 return persistenceStructureService;
 412  
         }
 413  
 
 414  
         /**
 415  
          * Sets the persistenceStructureService attribute value.
 416  
          * 
 417  
          * @param persistenceStructureService
 418  
          *            The persistenceStructureService to set.
 419  
          */
 420  
         public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
 421  0
                 this.persistenceStructureService = persistenceStructureService;
 422  0
         }
 423  
 
 424  
         private PersistableBusinessObject reattachAndSave(PersistableBusinessObject bo) {
 425  0
                 PersistableBusinessObject attachedBo = findByPrimaryKey(bo.getClass(), MetadataManager.getEntityPrimaryKeyValuePairs(bo));
 426  0
                 PersistableBusinessObject newBo = attachedBo;
 427  0
                 if (attachedBo == null) {
 428  0
                         newBo = entityManager.merge(bo);
 429  0
                         if (bo.getExtension() != null) {
 430  0
                                 entityManager.merge(bo.getExtension());
 431  
                         }
 432  
                 } else {
 433  
                         /*if (bo.getExtension() != null) {
 434  
                                 PersistableBusinessObject attachedBoe = findByPrimaryKey(bo.getExtension().getClass(), MetadataManager.getEntityPrimaryKeyValuePairs(bo.getExtension()));
 435  
                                 OrmUtils.reattach(bo.getExtension(),attachedBoe);
 436  
                                 attachedBo.setExtension((PersistableBusinessObjectExtension) attachedBoe);
 437  
                                 entityManager.merge(attachedBoe);
 438  
                         }*/
 439  0
                         OrmUtils.reattach(bo, attachedBo);
 440  0
                         newBo = entityManager.merge(attachedBo);
 441  
                 }
 442  0
                 return newBo;
 443  
         }
 444  
 
 445  
     /**
 446  
      * @return the entityManager
 447  
      */
 448  
     public EntityManager getEntityManager() {
 449  0
         return this.entityManager;
 450  
     }
 451  
 
 452  
     /**
 453  
      * @param entityManager the entityManager to set
 454  
      */
 455  
     public void setEntityManager(EntityManager entityManager) {
 456  0
         this.entityManager = entityManager;
 457  0
     }
 458  
         
 459  
 }