View Javadoc
1   package org.kuali.rice.krad.dao.impl;
2   
3   import org.apache.commons.lang.StringUtils;
4   import org.apache.ojb.broker.query.Criteria;
5   import org.apache.ojb.broker.query.QueryByCriteria;
6   import org.apache.ojb.broker.query.QueryFactory;
7   import org.kuali.rice.core.framework.persistence.ojb.dao.PlatformAwareDaoBaseOjb;
8   import org.kuali.rice.kns.service.KNSServiceLocator;
9   import org.kuali.rice.krad.bo.BusinessObject;
10  import org.kuali.rice.krad.bo.PersistableBusinessObject;
11  import org.kuali.rice.krad.dao.BusinessObjectDao;
12  import org.kuali.rice.krad.service.PersistenceStructureService;
13  import org.kuali.rice.krad.service.util.OjbCollectionAware;
14  import org.kuali.rice.krad.service.util.OjbCollectionHelper;
15  import org.kuali.rice.krad.util.KRADPropertyConstants;
16  import org.kuali.rice.krad.util.ObjectUtils;
17  import org.springframework.dao.DataAccessException;
18  import org.springframework.orm.ObjectRetrievalFailureException;
19  
20  import java.lang.reflect.InvocationTargetException;
21  import java.util.*;
22  
23  /**
24   * Created by angelind on 11/6/14.
25   *
26   * Overridden by 'Sheik Salahudeen'
27   * Overridden for fixing the document fetching issue in KRAD Transaction document with OJB.
28   * Modified method names: findBySinglePrimaryKey,findByPrimaryKey,findAll,findAllOrderBy,findMatching,findAllActive,findAllInactive,findAllActiveOrderBy,findMatchingActive,findMatchingOrderBy,findByPrimaryKeyUsingKeyObject,buildCriteria
29   * Changes description : Modified the return type of method from '<T extends BusinessObject>' to  '<T>'.
30   */
31  @Deprecated
32  public class BusinessObjectDaoOjb extends PlatformAwareDaoBaseOjb implements BusinessObjectDao, OjbCollectionAware {
33      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(BusinessObjectDaoOjb.class);
34  
35      private PersistenceStructureService persistenceStructureService;
36      private OjbCollectionHelper ojbCollectionHelper;
37  
38      /**
39       * This constructs a {@link BusinessObjectDaoOjb}
40       */
41      public BusinessObjectDaoOjb(PersistenceStructureService persistenceStructureService) {
42          this.persistenceStructureService = persistenceStructureService;
43      }
44  
45      /**
46       * @see org.kuali.rice.krad.dao.BusinessObjectDao#findBySinglePrimaryKey(java.lang.Class, java.lang.Object)
47       */
48      public <T> T findBySinglePrimaryKey(Class<T> clazz, Object primaryKey) {
49          if (primaryKey.getClass().getName().startsWith("java.lang.")
50                  || primaryKey.getClass().getName().startsWith("java.sql.")
51                  || primaryKey.getClass().getName().startsWith("java.math.")
52                  || primaryKey.getClass().getName().startsWith("java.util.")) {
53              try {
54                  return (T) getPersistenceBrokerTemplate().getObjectById(clazz, primaryKey);
55              } catch (  ObjectRetrievalFailureException ex  ) {
56                  // it doesn't exist, just return null
57                  return null;
58              }
59          } else {
60              Criteria criteria = buildCriteria(clazz, primaryKey);
61  
62              return (T) getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQuery(clazz, criteria));
63          }
64      }
65  
66      /**
67       * @see org.kuali.rice.krad.dao.BusinessObjectDao#findByPrimaryKey(java.lang.Class, java.util.Map)
68       */
69      public <T> T findByPrimaryKey(Class<T> clazz, Map<String, ?> primaryKeys) {
70          Criteria criteria = buildCriteria(primaryKeys);
71  
72          return (T) getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQuery(clazz, criteria));
73      }
74  
75      /**
76       * Retrieves all of the records for a given class name.
77       *
78       * @param clazz - the name of the object being used, either KualiCodeBase or a subclass
79       * @return Collection
80       * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAll(java.lang.Class)
81       */
82      public <T> Collection<T> findAll(Class<T> clazz) {
83          return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, (Criteria) null));
84      }
85  
86      /**
87       * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllOrderBy(java.lang.Class, java.lang.String, boolean)
88       */
89      public <T> Collection<T> findAllOrderBy(Class<T> clazz, String sortField, boolean sortAscending) {
90          QueryByCriteria queryByCriteria = new QueryByCriteria(clazz, (Criteria) null);
91  
92          if (sortAscending) {
93              queryByCriteria.addOrderByAscending(sortField);
94          }
95          else {
96              queryByCriteria.addOrderByDescending(sortField);
97          }
98  
99          return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(queryByCriteria);
100     }
101 
102     /**
103      * This is the default impl that comes with Kuali - uses OJB.
104      *
105      * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatching(java.lang.Class, java.util.Map)
106      */
107     public <T> Collection<T> findMatching(Class<T> clazz, Map<String, ?> fieldValues) {
108         Criteria criteria = buildCriteria(fieldValues);
109 
110         return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, criteria));
111     }
112 
113     /**
114      * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllActive(java.lang.Class)
115      */
116     public <T> Collection<T> findAllActive(Class<T> clazz) {
117         return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, buildActiveCriteria()));
118     }
119 
120     /**
121      * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllActive(java.lang.Class)
122      */
123     public <T> Collection<T> findAllInactive(Class<T> clazz) {
124         return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, buildInactiveCriteria()));
125     }
126 
127     /**
128      * @see org.kuali.rice.krad.dao.BusinessObjectDao#findAllActiveOrderBy(java.lang.Class, java.lang.String, boolean)
129      */
130     public <T> Collection<T> findAllActiveOrderBy(Class<T> clazz, String sortField, boolean sortAscending) {
131         QueryByCriteria queryByCriteria = new QueryByCriteria(clazz, buildActiveCriteria());
132 
133         if (sortAscending) {
134             queryByCriteria.addOrderByAscending(sortField);
135         }
136         else {
137             queryByCriteria.addOrderByDescending(sortField);
138         }
139 
140         return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(queryByCriteria);
141     }
142 
143     /**
144      * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatchingActive(java.lang.Class, java.util.Map)
145      */
146     public <T> Collection<T> findMatchingActive(Class<T> clazz, Map<String, ?> fieldValues) {
147         Criteria criteria = buildCriteria(fieldValues);
148         criteria.addAndCriteria(buildActiveCriteria());
149 
150         return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, criteria));
151     }
152 
153     /**
154      * This is the default impl that comes with Kuali - uses OJB.
155      *
156      * @see org.kuali.rice.krad.dao.BusinessObjectDao#countMatching(java.lang.Class, java.util.Map)
157      */
158     public int countMatching(Class clazz, Map<String, ?> fieldValues) {
159         Criteria criteria = buildCriteria(fieldValues);
160 
161         return getPersistenceBrokerTemplate().getCount(QueryFactory.newQuery(clazz, criteria));
162     }
163 
164     /**
165      * This is the default impl that comes with Kuali - uses OJB.
166      *
167      * @see org.kuali.rice.krad.dao.BusinessObjectDao#countMatching(java.lang.Class, java.util.Map, java.util.Map)
168      */
169     public int countMatching(Class clazz, Map<String, ?> positiveFieldValues, Map<String, ?> negativeFieldValues) {
170         Criteria criteria = buildCriteria(positiveFieldValues);
171         Criteria negativeCriteria = buildNegativeCriteria(negativeFieldValues);
172         criteria.addAndCriteria(negativeCriteria);
173         return getPersistenceBrokerTemplate().getCount(QueryFactory.newQuery(clazz, criteria));
174     }
175 
176 
177     /**
178      * This is the default impl that comes with Kuali - uses OJB.
179      *
180      * @see org.kuali.rice.krad.dao.BusinessObjectDao#findMatching(java.lang.Class, java.util.Map)
181      */
182     public <T> Collection<T> findMatchingOrderBy(Class<T> clazz, Map<String, ?> fieldValues, String sortField, boolean sortAscending) {
183         Criteria criteria = buildCriteria(fieldValues);
184         QueryByCriteria queryByCriteria = new QueryByCriteria(clazz, criteria);
185 
186         if (sortAscending) {
187             queryByCriteria.addOrderByAscending(sortField);
188         }
189         else {
190             queryByCriteria.addOrderByDescending(sortField);
191         }
192 
193         return (Collection<T>)getPersistenceBrokerTemplate().getCollectionByQuery(queryByCriteria);
194     }
195 
196     /**
197      * Saves a business object.
198      *
199      * @see org.kuali.rice.krad.dao.BusinessObjectDao#save(org.kuali.rice.krad.bo.PersistableBusinessObject)
200      */
201     public PersistableBusinessObject save(PersistableBusinessObject bo) throws DataAccessException {
202         // if collections exist on the BO, create a copy and use to process the
203         // collections to ensure
204         // that removed elements are deleted from the database
205         Set<String> boCollections = getPersistenceStructureService().listCollectionObjectTypes(bo.getClass()).keySet();
206         PersistableBusinessObject savedBo = null;
207         if (!boCollections.isEmpty()) {
208             // refresh bo to get db copy of collections
209             savedBo = (PersistableBusinessObject) ObjectUtils.deepCopy(bo);
210             for (String boCollection : boCollections) {
211                 if (getPersistenceStructureService().isCollectionUpdatable(savedBo.getClass(), boCollection)) {
212                     savedBo.refreshReferenceObject(boCollection);
213                 }
214             }
215             getOjbCollectionHelper().processCollections(this, bo, savedBo);
216         }
217 
218         getPersistenceBrokerTemplate().store(bo);
219         return bo;
220     }
221 
222     /**
223      * Saves a business object.
224      *
225      * @see org.kuali.rice.krad.dao.BusinessObjectDao#save(org.kuali.rice.krad.bo.PersistableBusinessObject)
226      */
227     public List<? extends PersistableBusinessObject> save(List businessObjects) throws DataAccessException {
228         if ( LOG.isDebugEnabled() ) {
229             LOG.debug( "About to persist the following BOs:" );
230             for ( Object bo : businessObjects ) {
231                 LOG.debug( "   --->" + bo );
232             }
233         }
234         for (Iterator i = businessObjects.iterator(); i.hasNext();) {
235             Object bo = i.next();
236             getPersistenceBrokerTemplate().store(bo);
237         }
238         return businessObjects;
239     }
240 
241 
242     /**
243      * Deletes the business object passed in.
244      *
245      * @param bo
246      * @throws DataAccessException
247      * @see org.kuali.rice.krad.dao.BusinessObjectDao#delete(org.kuali.rice.krad.bo.PersistableBusinessObject)
248      */
249     public void delete(Object bo) {
250         getPersistenceBrokerTemplate().delete(bo);
251     }
252 
253     /**
254      * @see org.kuali.rice.krad.dao.BusinessObjectDao#delete(java.util.List)
255      */
256     public void delete(List<? extends PersistableBusinessObject> boList) {
257         for (PersistableBusinessObject bo : boList) {
258             getPersistenceBrokerTemplate().delete(bo);
259         }
260     }
261 
262 
263     /**
264      * @see org.kuali.rice.krad.dao.BusinessObjectDao#deleteMatching(java.lang.Class, java.util.Map)
265      */
266     public void deleteMatching(Class clazz, Map<String, ?> fieldValues) {
267         Criteria criteria = buildCriteria(fieldValues);
268 
269         getPersistenceBrokerTemplate().deleteByQuery(QueryFactory.newQuery(clazz, criteria));
270 
271         // An ojb delete by query doesn't update the cache so we need to clear the cache for everything to work property.
272         // don't believe me? Read the source code to OJB
273         getPersistenceBrokerTemplate().clearCache();
274     }
275 
276     /**
277      * @see org.kuali.rice.krad.dao.BusinessObjectDao#retrieve(org.kuali.rice.krad.bo.PersistableBusinessObject)
278      */
279     public Object retrieve(Object object) {
280         return getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQueryByIdentity(object));
281     }
282 
283     /**
284      * OJB does not support this method
285      * @see org.kuali.rice.krad.dao.BusinessObjectDao#findByPrimaryKey(java.lang.Class, java.lang.Object)
286      */
287     public  <T> T findByPrimaryKeyUsingKeyObject(Class<T> clazz, Object pkObject) {
288         throw new UnsupportedOperationException("OJB does not support this option");
289     }
290 
291     /**
292      * No need to do anything - avoid saving and OJB will "manage read only"
293      * @see org.kuali.rice.krad.dao.BusinessObjectDao#manageReadOnly(org.kuali.rice.krad.bo.PersistableBusinessObject)
294      */
295     public PersistableBusinessObject manageReadOnly(PersistableBusinessObject bo) {
296         return bo;
297     }
298 
299     /**
300      * This method will build out criteria in the key-value paradigm (attribute-value).
301      *
302      * @param fieldValues
303      * @return
304      */
305     private Criteria buildCriteria(Map<String, ?> fieldValues) {
306         Criteria criteria = new Criteria();
307         for (Iterator i = fieldValues.entrySet().iterator(); i.hasNext();) {
308             Map.Entry<String, Object> e = (Map.Entry<String, Object>) i.next();
309 
310             String key = e.getKey();
311             Object value = e.getValue();
312             if (value instanceof Collection) {
313                 criteria.addIn(key, (Collection) value);
314             } else {
315                 criteria.addEqualTo(key, value);
316             }
317         }
318 
319         return criteria;
320     }
321 
322 
323     private <T> Criteria buildCriteria(Class<T> clazz, Object primaryKey) {
324         Map<String, Object> fieldValues = new HashMap<String, Object>();
325         List<String> fieldNames = getPersistenceStructureService().getPrimaryKeys(clazz);
326 
327         //create map of values
328         for (String fieldName : fieldNames) {
329             Object fieldValue;
330 
331             try {
332                 fieldValue = primaryKey.getClass().getMethod("get" + StringUtils.capitalize(fieldName)).invoke(primaryKey);
333                 fieldValues.put(fieldName, fieldValue);
334             } catch (IllegalArgumentException e) {
335                 e.printStackTrace();
336             } catch (IllegalAccessException e) {
337                 e.printStackTrace();
338             } catch (SecurityException e) {
339                 e.printStackTrace();
340             } catch (InvocationTargetException e) {
341                 e.printStackTrace();
342             } catch (NoSuchMethodException e) {
343                 e.printStackTrace();
344             }
345         }
346         return this.buildCriteria(fieldValues);
347     }
348 
349     /**
350      * Builds a Criteria object for active field set to true
351      * @return Criteria
352      */
353     private Criteria buildActiveCriteria(){
354         Criteria criteria = new Criteria();
355         criteria.addEqualTo(KRADPropertyConstants.ACTIVE, true);
356 
357         return criteria;
358     }
359 
360     /**
361      * Builds a Criteria object for active field set to true
362      * @return Criteria
363      */
364     private Criteria buildInactiveCriteria(){
365         Criteria criteria = new Criteria();
366         criteria.addEqualTo(KRADPropertyConstants.ACTIVE, false);
367 
368         return criteria;
369     }
370 
371     /**
372      * This method will build out criteria in the key-value paradigm (attribute-value).
373      *
374      * @param negativeFieldValues
375      * @return
376      */
377     private Criteria buildNegativeCriteria(Map<String, ?> negativeFieldValues) {
378         Criteria criteria = new Criteria();
379         for (Iterator i = negativeFieldValues.entrySet().iterator(); i.hasNext();) {
380             Map.Entry<String, Object> e = (Map.Entry<String, Object>) i.next();
381 
382             String key = e.getKey();
383             Object value = e.getValue();
384             if (value instanceof Collection) {
385                 criteria.addNotIn(key, (Collection) value);
386             }
387             else {
388                 criteria.addNotEqualTo(key, value);
389             }
390         }
391 
392         return criteria;
393     }
394 
395     /**
396      * Gets the persistenceStructureService attribute.
397      * @return Returns the persistenceStructureService.
398      */
399     protected PersistenceStructureService getPersistenceStructureService() {
400         return persistenceStructureService;
401     }
402 
403     /**
404      * Sets the persistenceStructureService attribute value.
405      * @param persistenceStructureService The persistenceStructureService to set.
406      */
407     public void setPersistenceStructureService(PersistenceStructureService persistenceStructureService) {
408         this.persistenceStructureService = persistenceStructureService;
409     }
410 
411     /**
412      * OJB collection helper instance which processes collections before persisting
413      *
414      * @return OjbCollectionHelper
415      */
416     protected OjbCollectionHelper getOjbCollectionHelper() {
417         if (ojbCollectionHelper == null) {
418             ojbCollectionHelper = KNSServiceLocator.getOjbCollectionHelper();
419         }
420 
421         return ojbCollectionHelper;
422     }
423 
424     /**
425      * Setter for the OJB collection helper
426      *
427      * @param ojbCollectionHelper
428      */
429     public void setOjbCollectionHelper(OjbCollectionHelper ojbCollectionHelper) {
430         this.ojbCollectionHelper = ojbCollectionHelper;
431     }
432 }