Refactored ISearchableDao to make it more generic, then added it and implementations...
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / common / CdmEntityDaoBase.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.persistence.dao.hibernate.common;
11
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.UUID;
18
19 import org.apache.log4j.Logger;
20 import org.apache.lucene.search.Sort;
21 import org.apache.lucene.search.SortField;
22 import org.hibernate.Criteria;
23 import org.hibernate.HibernateException;
24 import org.hibernate.NonUniqueObjectException;
25 import org.hibernate.Query;
26 import org.hibernate.Session;
27 import org.hibernate.criterion.Order;
28 import org.hibernate.criterion.Projections;
29 import org.hibernate.criterion.Restrictions;
30 import org.hibernate.envers.query.AuditQuery;
31 import org.hibernate.search.FullTextQuery;
32 import org.springframework.beans.factory.annotation.Autowired;
33 import org.springframework.beans.factory.annotation.Qualifier;
34 import org.springframework.dao.DataAccessException;
35 import org.springframework.stereotype.Repository;
36
37 import eu.etaxonomy.cdm.model.common.CdmBase;
38 import eu.etaxonomy.cdm.persistence.dao.BeanInitializer;
39 import eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao;
40 import eu.etaxonomy.cdm.persistence.query.OrderHint;
41
42
43 /**
44 * @author a.mueller
45 * FIXME CdmEntityDaoBase is abstract, can it be annotated with @Repository?
46 */
47 @Repository
48 public abstract class CdmEntityDaoBase<T extends CdmBase> extends DaoBase implements ICdmEntityDao<T> {
49 private static final Logger logger = Logger.getLogger(CdmEntityDaoBase.class);
50
51 int flushAfterNo = 1000; //large numbers may cause synchronisation errors when commiting the session !!
52 protected Class<T> type;
53
54 @Autowired
55 @Qualifier("defaultBeanInitializer")
56 protected BeanInitializer defaultBeanInitializer;
57
58
59 public CdmEntityDaoBase(Class<T> type){
60 this.type = type;
61 logger.debug("Creating DAO of type [" + type.getSimpleName() + "]");
62 }
63
64 //TODO this method should be moved to a concrete class (not typed)
65 public UUID saveCdmObj(CdmBase cdmObj) throws DataAccessException {
66 getSession().saveOrUpdate(cdmObj);
67 return cdmObj.getUuid();
68 }
69
70 //TODO: Replace saveCdmObj() by saveCdmObject_
71 private UUID saveCdmObject_(T cdmObj){
72 getSession().saveOrUpdate(cdmObj);
73 return cdmObj.getUuid();
74 }
75
76 //TODO: Use everywhere CdmEntityDaoBase.saveAll() instead of ServiceBase.saveCdmObjectAll()?
77 public Map<UUID, T> saveAll(Collection<T> cdmObjCollection){
78 int types = cdmObjCollection.getClass().getTypeParameters().length;
79 if (types > 0){
80 if (logger.isDebugEnabled()){logger.debug("ClassType: + " + cdmObjCollection.getClass().getTypeParameters()[0]);}
81 }
82
83 Map<UUID, T> resultMap = new HashMap<UUID, T>();
84 Iterator<T> iterator = cdmObjCollection.iterator();
85 int i = 0;
86 while(iterator.hasNext()){
87 if ( ( (i % 2000) == 0) && (i > 0) ){logger.debug("Saved " + i + " objects" );}
88 T cdmObj = iterator.next();
89 UUID uuid = saveCdmObject_(cdmObj);
90 if (logger.isDebugEnabled()){logger.debug("Save cdmObj: " + (cdmObj == null? null: cdmObj.toString()));}
91 resultMap.put(uuid, cdmObj);
92 i++;
93 if ( (i % flushAfterNo) == 0){
94 try{
95 logger.debug("flush");
96 flush();
97 }catch(Exception e){
98 logger.error("UUUIIIII");
99 e.printStackTrace();
100 }
101 }
102 }
103
104 if ( logger.isInfoEnabled() ){logger.info("Saved " + i + " objects" );}
105 return resultMap;
106 }
107
108
109 public UUID saveOrUpdate(T transientObject) throws DataAccessException {
110 try {
111 if (logger.isDebugEnabled()){logger.debug("dao saveOrUpdate start...");}
112 if (logger.isDebugEnabled()){logger.debug("transientObject(" + transientObject.getClass().getSimpleName() + ") ID:" + transientObject.getId() + ", UUID: " + transientObject.getUuid()) ;}
113 Session session = getSession();
114 session.saveOrUpdate(transientObject);
115 if (logger.isDebugEnabled()){logger.debug("dao saveOrUpdate end");}
116 return transientObject.getUuid();
117 } catch (NonUniqueObjectException e) {
118 logger.error("Error in CdmEntityDaoBase.saveOrUpdate(obj)");
119 logger.error(e.getIdentifier());
120 logger.error(e.getEntityName());
121 logger.error(e.getMessage());
122 e.printStackTrace();
123 throw e;
124 } catch (HibernateException e) {
125
126 e.printStackTrace();
127 throw e;
128 }
129 }
130
131 public UUID save(T newInstance) throws DataAccessException {
132 getSession().save(newInstance);
133 return newInstance.getUuid();
134 }
135
136 public UUID update(T transientObject) throws DataAccessException {
137 getSession().update(transientObject);
138 return transientObject.getUuid();
139 }
140
141 public UUID refresh(T persistentObject) throws DataAccessException {
142 getSession().refresh(persistentObject);
143 return persistentObject.getUuid();
144 }
145
146 public UUID delete(T persistentObject) throws DataAccessException {
147 getSession().delete(persistentObject);
148 return persistentObject.getUuid();
149 }
150
151 public T findById(int id) throws DataAccessException {
152 return (T) getSession().get(type, id);
153 }
154
155 public T findByUuid(UUID uuid) throws DataAccessException{
156 Session session = getSession();
157 Criteria crit = session.createCriteria(type);
158 crit.add(Restrictions.eq("uuid", uuid));
159 crit.addOrder(Order.desc("created"));
160 List<T> results = crit.list();
161 if (results.isEmpty()){
162 return null;
163 }else{
164 return results.get(0);
165 }
166 }
167
168 public T load(UUID uuid) {
169 T bean = findByUuid(uuid);
170 if(bean == null)
171 return null;
172 defaultBeanInitializer.load(bean);
173
174 return bean;
175 }
176
177
178 public T load(UUID uuid, List<String> propertyPaths){
179 T bean = findByUuid(uuid);
180 if(bean == null)
181 return bean;
182
183 defaultBeanInitializer.initialize(bean, propertyPaths);
184
185 return bean;
186 }
187
188 public Boolean exists(UUID uuid) {
189 if (findByUuid(uuid)==null){
190 return false;
191 }
192 return true;
193 }
194
195 public int count() {
196 return count(type);
197 }
198
199 public <TYPE extends T> int count(Class<TYPE> type) {
200 Session session = getSession();
201 Criteria crit = session.createCriteria(type);
202 crit.setProjection(Projections.projectionList().add(Projections.rowCount()));
203 Integer nbrRows = (Integer) crit.uniqueResult();
204 return nbrRows.intValue();
205 }
206
207 public List<T> list(Integer limit, Integer start) {
208 return list(limit, start, null);
209 }
210
211 protected void addOrder(Criteria criteria, List<OrderHint> orderHints) {
212 if(orderHints != null){
213 for(OrderHint orderHint : orderHints){
214 Order order;
215 String assocObj = null, propname;
216 int pos;
217 if((pos = orderHint.getPropertyName().indexOf('.', 0)) >= 0){
218 assocObj = orderHint.getPropertyName().substring(0, pos);
219 propname = orderHint.getPropertyName().substring(pos + 1);
220 } else {
221 propname = orderHint.getPropertyName();
222 }
223 if(orderHint.isAscending()){
224 order = Order.asc(propname);
225 } else {
226 order = Order.desc(propname);
227 }
228 if(assocObj != null){
229 criteria.createCriteria(assocObj).addOrder(order);
230 } else {
231 criteria.addOrder(order);
232 }
233 }
234 }
235 }
236
237 protected void addOrder(FullTextQuery fullTextQuery, List<OrderHint> orderHints) {
238 if(orderHints != null && !orderHints.isEmpty()) {
239 org.apache.lucene.search.Sort sort = new Sort();
240 SortField[] sortFields = new SortField[orderHints.size()];
241 for(int i = 0; i < orderHints.size(); i++) {
242 OrderHint orderHint = orderHints.get(i);
243 switch(orderHint.getSortOrder()) {
244 case ASCENDING:
245 sortFields[i] = new SortField(orderHint.getPropertyName() + "_forSort", false);
246 case DESCENDING:
247 sortFields[i] = new SortField(orderHint.getPropertyName() + "_forSort",true);
248 }
249 }
250 sort.setSort(sortFields);
251 fullTextQuery.setSort(sort);
252 }
253 }
254
255 public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints) {
256 return list(limit,start,orderHints,null);
257 }
258
259 public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
260 Criteria criteria = getSession().createCriteria(type);
261 if(limit != null) {
262 criteria.setFirstResult(start);
263 criteria.setMaxResults(limit);
264 }
265
266 addOrder(criteria,orderHints);
267 List<T> results = (List<T>)criteria.list();
268
269 defaultBeanInitializer.initializeAll(results, propertyPaths);
270 return results;
271 }
272
273 public <TYPE extends T> List<TYPE> list(Class<TYPE> type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
274 Criteria crit = getSession().createCriteria(type);
275 if(limit != null) {
276 crit.setFirstResult(start);
277 crit.setMaxResults(limit);
278 }
279
280 addOrder(crit,orderHints);
281
282 List<TYPE> results = (List<TYPE>)crit.list();
283 defaultBeanInitializer.initializeAll(results, propertyPaths);
284 return results;
285 }
286
287 public <TYPE extends T> List<TYPE> list(Class<TYPE> type, Integer limit, Integer start, List<OrderHint> orderHints) {
288 return list(type,limit,start,orderHints,null);
289 }
290
291 public <TYPE extends T> List<TYPE> list(Class<TYPE> type, Integer limit, Integer start) {
292 return list(type,limit,start,null,null);
293 }
294
295 public List<T> rows(String tableName, int limit, int start) {
296 Query query = getSession().createQuery("from " + tableName + " order by uuid");
297 query.setFirstResult(start);
298 query.setMaxResults(limit);
299 List<T> result = query.list();
300 return result;
301 }
302
303 public Class<T> getType() {
304 return type;
305 }
306
307 protected void setPagingParameter(Query query, Integer pageSize, Integer pageNumber){
308 if(pageSize != null) {
309 query.setMaxResults(pageSize);
310 if(pageNumber != null) {
311 query.setFirstResult(pageNumber * pageSize);
312 } else {
313 query.setFirstResult(0);
314 }
315 }
316 }
317
318 protected void setPagingParameter(AuditQuery query, Integer pageSize, Integer pageNumber){
319 if(pageSize != null) {
320 query.setMaxResults(pageSize);
321 if(pageNumber != null) {
322 query.setFirstResult(pageNumber * pageSize);
323 } else {
324 query.setFirstResult(0);
325 }
326 }
327 }
328 }