View Javadoc

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.core.dao.impl;
17  
18  import java.util.Collection;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.log4j.Logger;
24  import org.apache.ojb.broker.query.Criteria;
25  import org.apache.ojb.broker.query.Query;
26  import org.apache.ojb.broker.query.QueryByCriteria;
27  import org.apache.ojb.broker.query.QueryFactory;
28  import org.kuali.rice.core.config.Config;
29  import org.kuali.rice.core.config.ConfigContext;
30  import org.kuali.rice.core.dao.GenericDao;
31  import org.kuali.rice.core.database.platform.DatabasePlatform;
32  import org.kuali.rice.core.ojb.SuffixableQueryByCriteria;
33  import org.kuali.rice.core.util.RiceConstants;
34  import org.springframework.dao.DataAccessException;
35  import org.springmodules.orm.ojb.support.PersistenceBrokerDaoSupport;
36  
37  /**
38   * This class is the OJB implementation of the GenericDao interface. This
39   * class was adapted from the Kuali Nervous System
40   * (org.kuali.rice.kns.dao.impl.GenericDaoOjb).
41   * 
42   * @author Kuali Rice Team (rice.collab@kuali.org)
43   */
44  public class GenericDaoOjb extends PersistenceBrokerDaoSupport implements GenericDao {
45      private static final Logger LOG = Logger.getLogger(GenericDaoOjb.class);
46  
47      private boolean useSelectForUpdate = true;
48  
49      /**
50       * @param selectForUpdate whether to use select for update to implement pessimistic locking (testing/debugging purposes only)
51       */
52      public void setUseSelectForUpdate(boolean useSelectForUpdate) {
53          this.useSelectForUpdate = useSelectForUpdate;
54      }
55  
56      /**
57       * @see org.kuali.rice.core.dao.GenericDao#findById(Class, Object)
58       */
59      public Object findById(Class clazz, Object id) {
60          return getPersistenceBrokerTemplate().getObjectById(clazz, id);
61      }
62  
63      /**
64       * @see org.kuali.rice.core.dao.GenericDao#findByPrimaryKey(java.lang.Class, java.util.Map)
65       */
66      public Object findByPrimaryKey(Class clazz, Map primaryKeys) {
67          Criteria criteria = buildCriteria(primaryKeys);
68  
69          return getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQuery(clazz, criteria));
70      }
71  
72      /**
73       * @see org.kuali.rice.core.dao.GenericDao#findByUniqueKey(java.lang.Class, java.util.Map)
74       */
75      public Object findByUniqueKey(Class clazz, Map uniqueKeys) {
76          Criteria criteria = buildCriteria(uniqueKeys);
77  
78          return getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQuery(clazz, criteria));
79      }
80  
81      /**
82       * @see org.kuali.rice.core.dao.GenericDao#findAll(java.lang.Class)
83       */
84      public Collection findAll(Class clazz) {
85          return getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, (Criteria) null));
86      }
87  
88      /**
89       * @see org.kuali.rice.core.dao.GenericDao#findAllOrderBy(java.lang.Class, java.lang.String, boolean)
90       */
91      public Collection findAllOrderBy(Class clazz, String sortField,
92              boolean sortAscending) {
93          QueryByCriteria queryByCriteria = new QueryByCriteria(clazz, (Criteria) null);
94  
95          if (sortAscending) {
96              queryByCriteria.addOrderByAscending(sortField);
97          } else {
98              queryByCriteria.addOrderByDescending(sortField);
99          }
100 
101         return getPersistenceBrokerTemplate().getCollectionByQuery(
102                 queryByCriteria);
103     }
104 
105     /**
106      * @see org.kuali.rice.core.dao.GenericDao#findMatching(java.lang.Class, java.util.Map)
107      */
108     public Collection findMatching(Class clazz, Map fieldValues) {
109         Criteria criteria = buildCriteria(fieldValues);
110 
111         return getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQuery(clazz, criteria));
112     }
113 
114     /**
115      * @see org.kuali.rice.core.dao.GenericDao#countMatching(java.lang.Class, java.util.Map)
116      */
117     public int countMatching(Class clazz, Map fieldValues) {
118         Criteria criteria = buildCriteria(fieldValues);
119 
120         return getPersistenceBrokerTemplate().getCount(QueryFactory.newQuery(clazz, criteria));
121     }
122 
123     /**
124      * @see org.kuali.rice.core.dao.GenericDao#countMatching(java.lang.Class, java.util.Map, java.util.Map)
125      */
126     public int countMatching(Class clazz, Map positiveFieldValues,
127             Map negativeFieldValues) {
128         Criteria criteria = buildCriteria(positiveFieldValues);
129         Criteria negativeCriteria = buildNegativeCriteria(negativeFieldValues);
130         criteria.addAndCriteria(negativeCriteria);
131         return getPersistenceBrokerTemplate().getCount(QueryFactory.newQuery(clazz, criteria));
132     }
133 
134     /**
135      * @see org.kuali.rice.core.dao.GenericDao#findMatchingOrderBy(java.lang.Class, java.util.Map, java.lang.String, boolean)
136      */
137     public Collection findMatchingOrderBy(Class clazz, Map fieldValues,
138             String sortField, boolean sortAscending) {
139         Criteria criteria = buildCriteria(fieldValues);
140         QueryByCriteria queryByCriteria = new QueryByCriteria(clazz, criteria);
141 
142         if (sortAscending) {
143             queryByCriteria.addOrderByAscending(sortField);
144         } else {
145             queryByCriteria.addOrderByDescending(sortField);
146         }
147 
148         return getPersistenceBrokerTemplate().getCollectionByQuery(queryByCriteria);
149     }
150 
151     /**
152      * @see org.kuali.rice.core.dao.GenericDao#save(java.lang.Object)
153      */
154     public void save(Object bo) throws DataAccessException {
155         getPersistenceBrokerTemplate().store(bo);
156     }
157 
158     /**
159      * @see org.kuali.rice.core.dao.GenericDao#save(java.util.List)
160      */
161     public void save(List businessObjects) throws DataAccessException {
162         for (Iterator i = businessObjects.iterator(); i.hasNext();) {
163             Object bo = i.next();
164             getPersistenceBrokerTemplate().store(bo);
165         }
166     }
167 
168     /**
169      * @see org.kuali.rice.core.dao.GenericDao#delete(java.lang.Object)
170      */
171     public void delete(Object bo) {
172         getPersistenceBrokerTemplate().delete(bo);
173     }
174 
175     /**
176      * @see org.kuali.rice.core.dao.GenericDao#delete(java.util.List)
177      */
178     public void delete(List<Object> boList) {
179         for (Object bo : boList) {
180             getPersistenceBrokerTemplate().delete(bo);
181         }
182     }
183 
184     /**
185      * @see org.kuali.rice.core.dao.GenericDao#deleteMatching(java.lang.Class, java.util.Map)
186      */
187     public void deleteMatching(Class clazz, Map fieldValues) {
188         Criteria criteria = buildCriteria(fieldValues);
189 
190         getPersistenceBrokerTemplate().deleteByQuery(QueryFactory.newQuery(clazz, criteria));
191 
192         // An ojb delete by query doesn't update the cache so we need to clear
193         // the cache for everything to work property.
194         // don't believe me? Read the source code to OJB
195         getPersistenceBrokerTemplate().clearCache();
196     }
197 
198     /**
199      * @see org.kuali.rice.core.dao.GenericDao#retrieve(java.lang.Object)
200      */
201     public Object retrieve(Object object) {
202         return getPersistenceBrokerTemplate().getObjectByQuery(QueryFactory.newQueryByIdentity(object));
203     }
204 
205     /**
206      * @see org.kuali.rice.core.dao.GenericDao#findMatchingByExample(java.lang.Object)
207      */
208     public Collection findMatchingByExample(Object object) {
209         return getPersistenceBrokerTemplate().getCollectionByQuery(QueryFactory.newQueryByExample(object));
210     }
211 
212     /**
213      * @see org.kuali.rice.core.dao.GenericDao#findMatching(java.lang.Class, org.apache.ojb.broker.query.Criteria)
214      */
215     public Collection findMatching(Class clazz, Criteria criteria) {
216         return findMatching(clazz, criteria, false, RiceConstants.NO_WAIT);
217         /*return getPersistenceBrokerTemplate().getCollectionByQuery(
218         QueryFactory.newQuery(clazz, criteria));*/
219     }
220 
221     /**
222      * @see org.kuali.rice.core.dao.GenericDao#findMatching(Class, Criteria, boolean)
223      */
224     public Collection findMatching(Class clazz, Criteria criteria, boolean selectForUpdate, long wait) {
225         Query query;
226         if (selectForUpdate && !useSelectForUpdate) {
227             LOG.warn("Pessimistic locking was requested but select for update is disabled");
228         }
229         if (selectForUpdate && useSelectForUpdate) {
230             SuffixableQueryByCriteria q = new SuffixableQueryByCriteria(clazz, criteria);
231             // XXX: hax
232             Config config = ConfigContext.getCurrentContextConfig();
233             DatabasePlatform platform = null;
234 			try {
235 				platform = (DatabasePlatform) Class.forName(config.getProperty(Config.DATASOURCE_PLATFORM)).newInstance();
236 			} catch (Exception e) {
237 				throw new RuntimeException(e.getMessage(), e);
238 			}
239             q.setQuerySuffix(" " + platform.getSelectForUpdateSuffix(wait));
240             query = q;            
241         } else {
242             query = QueryFactory.newQuery(clazz, criteria);
243         }
244         return getPersistenceBrokerTemplate().getCollectionByQuery(query);
245 
246     }
247 
248     /**
249      * This method will build out criteria in the key-value paradigm
250      * (attribute-value).
251      * 
252      * @param fieldValues
253      * @return
254      */
255     private Criteria buildCriteria(Map fieldValues) {
256         Criteria criteria = new Criteria();
257         for (Iterator i = fieldValues.entrySet().iterator(); i.hasNext();) {
258             Map.Entry e = (Map.Entry) i.next();
259 
260             String key = (String) e.getKey();
261             Object value = e.getValue();
262             if (value instanceof Collection) {
263                 criteria.addIn(key, (Collection) value);
264             } else {
265                 criteria.addEqualTo(key, value);
266             }
267         }
268 
269         return criteria;
270     }
271 
272     /**
273      * This method will build out criteria in the key-value paradigm
274      * (attribute-value).
275      * 
276      * @param fieldValues
277      * @return
278      */
279     private Criteria buildNegativeCriteria(Map negativeFieldValues) {
280         Criteria criteria = new Criteria();
281         for (Iterator i = negativeFieldValues.entrySet().iterator(); i.hasNext();) {
282             Map.Entry e = (Map.Entry) i.next();
283 
284             String key = (String) e.getKey();
285             Object value = e.getValue();
286             if (value instanceof Collection) {
287                 criteria.addNotIn(key, (Collection) value);
288             } else {
289                 criteria.addNotEqualTo(key, value);
290             }
291         }
292 
293         return criteria;
294     }
295 }