Merge branch 'develop' of ssh://dev.e-taxonomy.eu/var/git/cdmlib into develop
[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.lang.reflect.Field;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.UUID;
22
23 import org.apache.log4j.Logger;
24 import org.apache.lucene.search.Sort;
25 import org.apache.lucene.search.SortField;
26 import org.hibernate.Criteria;
27 import org.hibernate.FlushMode;
28 import org.hibernate.HibernateException;
29 import org.hibernate.LockOptions;
30 import org.hibernate.NonUniqueObjectException;
31 import org.hibernate.Query;
32 import org.hibernate.Session;
33 import org.hibernate.criterion.Criterion;
34 import org.hibernate.criterion.DetachedCriteria;
35 import org.hibernate.criterion.Example;
36 import org.hibernate.criterion.Example.PropertySelector;
37 import org.hibernate.criterion.Order;
38 import org.hibernate.criterion.ProjectionList;
39 import org.hibernate.criterion.Projections;
40 import org.hibernate.criterion.Restrictions;
41 import org.hibernate.envers.query.AuditQuery;
42 import org.hibernate.metadata.ClassMetadata;
43 import org.hibernate.search.FullTextQuery;
44 import org.hibernate.type.Type;
45 import org.joda.time.DateTime;
46 import org.springframework.beans.factory.annotation.Autowired;
47 import org.springframework.dao.DataAccessException;
48 import org.springframework.dao.InvalidDataAccessApiUsageException;
49 import org.springframework.security.core.Authentication;
50 import org.springframework.security.core.context.SecurityContextHolder;
51 import org.springframework.stereotype.Repository;
52 import org.springframework.util.ReflectionUtils;
53
54 import eu.etaxonomy.cdm.model.common.CdmBase;
55 import eu.etaxonomy.cdm.model.common.User;
56 import eu.etaxonomy.cdm.model.common.VersionableEntity;
57 import eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao;
58 import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
59 import eu.etaxonomy.cdm.persistence.dto.MergeResult;
60 import eu.etaxonomy.cdm.persistence.hibernate.PostMergeEntityListener;
61 import eu.etaxonomy.cdm.persistence.hibernate.replace.ReferringObjectMetadata;
62 import eu.etaxonomy.cdm.persistence.hibernate.replace.ReferringObjectMetadataFactory;
63 import eu.etaxonomy.cdm.persistence.query.Grouping;
64 import eu.etaxonomy.cdm.persistence.query.MatchMode;
65 import eu.etaxonomy.cdm.persistence.query.OrderHint;
66
67
68 /**
69 * @author a.mueller
70 * FIXME CdmEntityDaoBase is abstract, can it be annotated with @Repository?
71 */
72 @Repository
73 public abstract class CdmEntityDaoBase<T extends CdmBase> extends DaoBase implements ICdmEntityDao<T> {
74 private static final Logger logger = Logger.getLogger(CdmEntityDaoBase.class);
75
76 protected int flushAfterNo = 1000; //large numbers may cause synchronisation errors when commiting the session !!
77
78 protected Class<T> type;
79
80 // protected Version version = Configuration.luceneVersion;
81
82 @Autowired
83 // @Qualifier("defaultBeanInitializer")
84 protected IBeanInitializer defaultBeanInitializer;
85
86 public void setDefaultBeanInitializer(IBeanInitializer defaultBeanInitializer) {
87 this.defaultBeanInitializer = defaultBeanInitializer;
88 }
89
90 @Autowired
91 private ReferringObjectMetadataFactory referringObjectMetadataFactory;
92
93
94 public CdmEntityDaoBase(Class<T> type){
95 this.type = type;
96 logger.debug("Creating DAO of type [" + type.getSimpleName() + "]");
97 }
98
99 @Override
100 public void lock(T t, LockOptions lockOptions) {
101 getSession().buildLockRequest(lockOptions).lock(t);
102 }
103
104 @Override
105 public void refresh(T t, LockOptions lockOptions, List<String> propertyPaths) {
106 getSession().refresh(t, lockOptions);
107 defaultBeanInitializer.initialize(t, propertyPaths);
108 }
109
110 //TODO this method should be moved to a concrete class (not typed)
111 public UUID saveCdmObj(CdmBase cdmObj) throws DataAccessException {
112 getSession().saveOrUpdate(cdmObj);
113 return cdmObj.getUuid();
114 }
115
116 //TODO: Replace saveCdmObj() by saveCdmObject_
117 private UUID saveCdmObject_(T cdmObj){
118 getSession().saveOrUpdate(cdmObj);
119 return cdmObj.getUuid();
120 }
121
122 //TODO: Use everywhere CdmEntityDaoBase.saveAll() instead of ServiceBase.saveCdmObjectAll()?
123 //TODO: why does this use saveCdmObject_ which actually savesOrUpdateds data ?
124 @Override
125 public Map<UUID, T> saveAll(Collection<T> cdmObjCollection){
126 int types = cdmObjCollection.getClass().getTypeParameters().length;
127 if (types > 0){
128 if (logger.isDebugEnabled()){logger.debug("ClassType: + " + cdmObjCollection.getClass().getTypeParameters()[0]);}
129 }
130
131 Map<UUID, T> resultMap = new HashMap<UUID, T>();
132 Iterator<T> iterator = cdmObjCollection.iterator();
133 int i = 0;
134 while(iterator.hasNext()){
135 if ( ( (i % 2000) == 0) && (i > 0) ){logger.debug("Saved " + i + " objects" );}
136 T cdmObj = iterator.next();
137 UUID uuid = saveCdmObject_(cdmObj);
138 if (logger.isDebugEnabled()){logger.debug("Save cdmObj: " + (cdmObj == null? null: cdmObj.toString()));}
139 resultMap.put(uuid, cdmObj);
140 i++;
141 if ( (i % flushAfterNo) == 0){
142 try{
143 if (logger.isDebugEnabled()){logger.debug("flush");}
144 flush();
145 }catch(Exception e){
146 logger.error("An exception occurred when trying to flush data");
147 e.printStackTrace();
148 throw new RuntimeException(e);
149 }
150 }
151 }
152
153 if ( logger.isInfoEnabled() ){logger.info("Saved " + i + " objects" );}
154 return resultMap;
155 }
156
157 private UUID saveOrUpdateCdmObject(T cdmObj){
158 getSession().saveOrUpdate(cdmObj);
159 return cdmObj.getUuid();
160 }
161
162 @Override
163 public Map<UUID, T> saveOrUpdateAll(Collection<T> cdmObjCollection){
164 int types = cdmObjCollection.getClass().getTypeParameters().length;
165 if (types > 0){
166 if (logger.isDebugEnabled()){logger.debug("ClassType: + " + cdmObjCollection.getClass().getTypeParameters()[0]);}
167 }
168
169 Map<UUID, T> resultMap = new HashMap<UUID, T>();
170 Iterator<T> iterator = cdmObjCollection.iterator();
171 int i = 0;
172 while(iterator.hasNext()){
173 if ( ( (i % 2000) == 0) && (i > 0) ){logger.debug("Saved " + i + " objects" );}
174 T cdmObj = iterator.next();
175 UUID uuid = saveOrUpdateCdmObject(cdmObj);
176 if (logger.isDebugEnabled()){logger.debug("Save cdmObj: " + (cdmObj == null? null: cdmObj.toString()));}
177 resultMap.put(uuid, cdmObj);
178 i++;
179 if ( (i % flushAfterNo) == 0){
180 try{
181 if (logger.isDebugEnabled()){logger.debug("flush");}
182 flush();
183 }catch(Exception e){
184 logger.error("An exception occurred when trying to flush data");
185 e.printStackTrace();
186 throw new RuntimeException(e);
187 }
188 }
189 }
190
191 if ( logger.isInfoEnabled() ){logger.info("Saved " + i + " objects" );}
192 return resultMap;
193 }
194
195
196
197
198 @Override
199 public T replace(T x, T y) {
200 if(x.equals(y)) {
201 return y;
202 }
203
204 Class<?> commonClass = x.getClass();
205 if(y != null) {
206 while(!commonClass.isAssignableFrom(y.getClass())) {
207 if(commonClass.equals(type)) {
208 throw new RuntimeException();
209 }
210 commonClass = commonClass.getSuperclass();
211 }
212 }
213
214 getSession().merge(x);
215
216 Set<ReferringObjectMetadata> referringObjectMetas = referringObjectMetadataFactory.get(x.getClass());
217
218 for(ReferringObjectMetadata referringObjectMetadata : referringObjectMetas) {
219
220 List<CdmBase> referringObjects = referringObjectMetadata.getReferringObjects(x, getSession());
221
222 for(CdmBase referringObject : referringObjects) {
223 try {
224 referringObjectMetadata.replace(referringObject,x,y);
225 getSession().update(referringObject);
226
227 } catch (IllegalArgumentException e) {
228 throw new RuntimeException(e.getMessage(),e);
229 } catch (IllegalAccessException e) {
230 throw new RuntimeException(e.getMessage(),e);
231 }
232 }
233 }
234 return y;
235 }
236
237 @Override
238 public Session getSession() throws DataAccessException {
239 return super.getSession();
240 }
241
242 @Override
243 public void clear() throws DataAccessException {
244 Session session = getSession();
245 session.clear();
246 if (logger.isDebugEnabled()){logger.debug("dao clear end");}
247 }
248
249 @Override
250 public MergeResult<T> merge(T transientObject, boolean returnTransientEntity) throws DataAccessException {
251 Session session = getSession();
252 PostMergeEntityListener.addSession(session);
253 MergeResult<T> result = null;
254 try {
255 @SuppressWarnings("unchecked")
256 T persistentObject = (T)session.merge(transientObject);
257 if (logger.isDebugEnabled()){logger.debug("dao merge end");}
258
259 if(returnTransientEntity) {
260 if(transientObject != null && persistentObject != null) {
261 transientObject.setId(persistentObject.getId());
262 }
263 result = new MergeResult(transientObject, PostMergeEntityListener.getNewEntities(session));
264 } else {
265 result = new MergeResult(persistentObject, null);
266 }
267 return result;
268 } finally {
269 PostMergeEntityListener.removeSession(session);
270 }
271 }
272
273 @Override
274 public T merge(T transientObject) throws DataAccessException {
275 Session session = getSession();
276 @SuppressWarnings("unchecked")
277 T persistentObject = (T)session.merge(transientObject);
278 if (logger.isDebugEnabled()){logger.debug("dao merge end");}
279 return persistentObject;
280 }
281
282 @Override
283 public UUID saveOrUpdate(T transientObject) throws DataAccessException {
284 if (transientObject == null){
285 logger.warn("Object to save should not be null. NOP");
286 return null;
287 }
288 try {
289 if (logger.isDebugEnabled()){logger.debug("dao saveOrUpdate start...");}
290 if (logger.isDebugEnabled()){logger.debug("transientObject(" + transientObject.getClass().getSimpleName() + ") ID:" + transientObject.getId() + ", UUID: " + transientObject.getUuid()) ;}
291 Session session = getSession();
292 if(transientObject.getId() != 0 && VersionableEntity.class.isAssignableFrom(transientObject.getClass())) {
293 VersionableEntity versionableEntity = (VersionableEntity)transientObject;
294 versionableEntity.setUpdated(new DateTime());
295 Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
296 if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {
297 User user = (User)authentication.getPrincipal();
298 versionableEntity.setUpdatedBy(user);
299 }
300 }
301 session.saveOrUpdate(transientObject);
302 if (logger.isDebugEnabled()){logger.debug("dao saveOrUpdate end");}
303 return transientObject.getUuid();
304 } catch (NonUniqueObjectException e) {
305 logger.error("Error in CdmEntityDaoBase.saveOrUpdate(obj)");
306 logger.error(e.getIdentifier());
307 logger.error(e.getEntityName());
308 logger.error(e.getMessage());
309
310 e.printStackTrace();
311 throw e;
312 } catch (HibernateException e) {
313
314 e.printStackTrace();
315 throw e;
316 }
317 }
318
319 @Override
320 public T save(T newInstance) throws DataAccessException {
321 if (newInstance == null){
322 logger.warn("Object to save should not be null. NOP");
323 return null;
324 }
325 getSession().save(newInstance);
326 return newInstance;
327 }
328
329 @Override
330 public UUID update(T transientObject) throws DataAccessException {
331 if (transientObject == null){
332 logger.warn("Object to update should not be null. NOP");
333 return null;
334 }
335 getSession().update(transientObject);
336 return transientObject.getUuid();
337 }
338
339 @Override
340 public UUID refresh(T persistentObject) throws DataAccessException {
341 getSession().refresh(persistentObject);
342 return persistentObject.getUuid();
343 }
344
345 @Override
346 public UUID delete(T persistentObject) throws DataAccessException {
347 if (persistentObject == null){
348 logger.warn(type.getName() + " was 'null'");
349 return null;
350 }
351
352 // Merge the object in if it is detached
353 //
354 // I think this is preferable to catching lazy initialization errors
355 // as that solution only swallows and hides the exception, but doesn't
356 // actually solve it.
357 persistentObject = (T) getSession().merge(persistentObject);
358 getSession().delete(persistentObject);
359 return persistentObject.getUuid();
360 }
361
362 @Override
363 public T findById(int id) throws DataAccessException {
364 return getSession().get(type, id);
365 }
366
367
368 @Override
369 public T findByUuid(UUID uuid) throws DataAccessException{
370 Session session = getSession();
371 Criteria crit = session.createCriteria(type);
372 crit.add(Restrictions.eq("uuid", uuid));
373 crit.addOrder(Order.desc("created"));
374 @SuppressWarnings("unchecked")
375 List<T> results = crit.list();
376 Set<T> resultSet = new HashSet<>();
377 resultSet.addAll(results);
378 if (resultSet.isEmpty()){
379 return null;
380 }else{
381 if(resultSet.size() > 1){
382 logger.error("findByUuid() delivers more than one result for UUID: " + uuid);
383 }
384 return results.get(0);
385 }
386 }
387
388 @Override
389 public T findByUuidWithoutFlush(UUID uuid) throws DataAccessException{
390 Session session = getSession();
391 FlushMode currentFlushMode = session.getFlushMode();
392 try {
393 // set flush mode to manual so that the session does not flush
394 // when before performing the query
395 session.setFlushMode(FlushMode.MANUAL);
396 Criteria crit = session.createCriteria(type);
397 crit.add(Restrictions.eq("uuid", uuid));
398 crit.addOrder(Order.desc("created"));
399 @SuppressWarnings("unchecked")
400 List<T> results = crit.list();
401 if (results.isEmpty()){
402 return null;
403 }else{
404 if(results.size() > 1){
405 logger.error("findByUuid() delivers more than one result for UUID: " + uuid);
406 }
407 return results.get(0);
408 }
409 } finally {
410 // set back the session flush mode
411 if(currentFlushMode != null) {
412 session.setFlushMode(currentFlushMode);
413 }
414 }
415 }
416
417 @Override
418 public List<T> loadList(Collection<Integer> ids, List<String> propertyPaths) throws DataAccessException {
419
420 if (ids.isEmpty()) {
421 return new ArrayList<T>(0);
422 }
423
424 Criteria criteria = prepareList(ids, null, null, null, "id");
425
426 if (logger.isDebugEnabled()){logger.debug(criteria.toString());}
427
428 @SuppressWarnings("unchecked")
429 List<T> result = criteria.list();
430 defaultBeanInitializer.initializeAll(result, propertyPaths);
431 return result;
432 }
433
434
435 @Override
436 public List<T> list(Collection<UUID> uuids, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws DataAccessException {
437
438 Criteria criteria = prepareList(uuids, pageSize, pageNumber, orderHints, "uuid");
439
440 @SuppressWarnings("unchecked")
441 List<T> result = criteria.list();
442 defaultBeanInitializer.initializeAll(result, propertyPaths);
443 return result;
444 }
445
446 /**
447 * @param uuids
448 * @param pageSize
449 * @param pageNumber
450 * @param orderHints
451 * @param propertyName
452 * @return
453 */
454 private Criteria prepareList(Collection<?> uuids, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, String propertyName) {
455 Criteria criteria = getSession().createCriteria(type);
456 criteria.add(Restrictions.in(propertyName, uuids));
457
458 if(pageSize != null) {
459 criteria.setMaxResults(pageSize);
460 if(pageNumber != null) {
461 criteria.setFirstResult(pageNumber * pageSize);
462 } else {
463 criteria.setFirstResult(0);
464 }
465 }
466
467 if(orderHints == null) {
468 orderHints = OrderHint.defaultOrderHintsFor(type);
469 }
470 addOrder(criteria, orderHints);
471 return criteria;
472 }
473
474
475 protected List<T> findByParam(Class<? extends T> clazz, String param, String queryString, MatchMode matchmode, List<Criterion> criterion, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
476 Criteria criteria = null;
477
478 if(clazz == null) {
479 criteria = getSession().createCriteria(type);
480 } else {
481 criteria = getSession().createCriteria(clazz);
482 }
483
484 if (queryString != null) {
485 if(matchmode == null) {
486 criteria.add(Restrictions.ilike(param, queryString));
487 } else if(matchmode == MatchMode.BEGINNING) {
488 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.START));
489 } else if(matchmode == MatchMode.END) {
490 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.END));
491 } else if(matchmode == MatchMode.EXACT) {
492 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.EXACT));
493 } else {
494 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.ANYWHERE));
495 }
496 }
497
498 addCriteria(criteria, criterion);
499
500 if(pageSize != null) {
501 criteria.setMaxResults(pageSize);
502 if(pageNumber != null) {
503 criteria.setFirstResult(pageNumber * pageSize);
504 } else {
505 criteria.setFirstResult(0);
506 }
507 }
508
509 addOrder(criteria, orderHints);
510
511 @SuppressWarnings("unchecked")
512 List<T> result = criteria.list();
513 defaultBeanInitializer.initializeAll(result, propertyPaths);
514 return result;
515 }
516
517 @Override
518 public T load(UUID uuid) {
519 T bean = findByUuid(uuid);
520 if(bean == null){
521 return null;
522 }
523 defaultBeanInitializer.load(bean);
524
525 return bean;
526 }
527
528 @Override
529 public T load(int id, List<String> propertyPaths){
530 T bean = findById(id);
531 if(bean == null){
532 return bean;
533 }
534 defaultBeanInitializer.initialize(bean, propertyPaths);
535
536 return bean;
537 }
538
539 @Override
540 public T load(UUID uuid, List<String> propertyPaths){
541 T bean = findByUuid(uuid);
542 if(bean == null){
543 return bean;
544 }
545 defaultBeanInitializer.initialize(bean, propertyPaths);
546
547 return bean;
548 }
549
550 @Override
551 public Boolean exists(UUID uuid) {
552 if (findByUuid(uuid)==null){
553 return false;
554 }
555 return true;
556 }
557
558 @Override
559 public int count() {
560 return count(type);
561 }
562
563 @Override
564 public int count(Class<? extends T> clazz) {
565 Session session = getSession();
566 Criteria criteria = null;
567 if(clazz == null) {
568 criteria = session.createCriteria(type);
569 } else {
570 criteria = session.createCriteria(clazz);
571 }
572 criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
573
574 //since hibernate 4 (or so) uniqueResult returns Long, not Integer, therefore needs
575 //to be casted. Think about returning long rather then int!
576 return ((Number) criteria.uniqueResult()).intValue();
577 }
578
579 @Override
580 public List<T> list(Integer limit, Integer start) {
581 return list(limit, start, null);
582 }
583
584 @Override
585 public List<Object[]> group(Class<? extends T> clazz,Integer limit, Integer start, List<Grouping> groups, List<String> propertyPaths) {
586
587 Criteria criteria = null;
588 if(clazz == null){
589 criteria = getSession().createCriteria(type);
590 } else {
591 criteria = getSession().createCriteria(clazz);
592 }
593
594 addGroups(criteria,groups);
595
596 if(limit != null) {
597 criteria.setFirstResult(start);
598 criteria.setMaxResults(limit);
599 }
600
601 @SuppressWarnings("unchecked")
602 List<Object[]> result = criteria.list();
603
604 if(propertyPaths != null && !propertyPaths.isEmpty()) {
605 for(Object[] objects : result) {
606 defaultBeanInitializer.initialize(objects[0], propertyPaths);
607 }
608 }
609
610 return result;
611 }
612
613 protected void countGroups(DetachedCriteria criteria,List<Grouping> groups) {
614 if(groups != null){
615
616
617 Map<String,String> aliases = new HashMap<String,String>();
618
619 for(Grouping grouping : groups) {
620 if(grouping.getAssociatedObj() != null) {
621 String alias = null;
622 if((alias = aliases.get(grouping.getAssociatedObj())) == null) {
623 alias = grouping.getAssociatedObjectAlias();
624 aliases.put(grouping.getAssociatedObj(), alias);
625 criteria.createAlias(grouping.getAssociatedObj(),alias);
626 }
627 }
628 }
629
630 ProjectionList projectionList = Projections.projectionList();
631
632 for(Grouping grouping : groups) {
633 grouping.addProjection(projectionList);
634 }
635 criteria.setProjection(projectionList);
636 }
637 }
638
639 protected void addGroups(Criteria criteria,List<Grouping> groups) {
640 if(groups != null){
641
642
643 Map<String,String> aliases = new HashMap<String,String>();
644
645 for(Grouping grouping : groups) {
646 if(grouping.getAssociatedObj() != null) {
647 String alias = null;
648 if((alias = aliases.get(grouping.getAssociatedObj())) == null) {
649 alias = grouping.getAssociatedObjectAlias();
650 aliases.put(grouping.getAssociatedObj(), alias);
651 criteria.createAlias(grouping.getAssociatedObj(),alias);
652 }
653 }
654 }
655
656 ProjectionList projectionList = Projections.projectionList();
657
658 for(Grouping grouping : groups) {
659 grouping.addProjection(projectionList);
660 }
661 criteria.setProjection(projectionList);
662
663 for(Grouping grouping : groups) {
664 grouping.addOrder(criteria);
665
666 }
667 }
668 }
669
670 protected void addCriteria(Criteria criteria, List<Criterion> criterion) {
671 if(criterion != null) {
672 for(Criterion c : criterion) {
673 criteria.add(c);
674 }
675 }
676
677 }
678
679 protected void addOrder(FullTextQuery fullTextQuery, List<OrderHint> orderHints) {
680 //FIXME preliminary hardcoded type:
681 SortField.Type type = SortField.Type.STRING;
682
683 if(orderHints != null && !orderHints.isEmpty()) {
684 org.apache.lucene.search.Sort sort = new Sort();
685 SortField[] sortFields = new SortField[orderHints.size()];
686 for(int i = 0; i < orderHints.size(); i++) {
687 OrderHint orderHint = orderHints.get(i);
688 switch(orderHint.getSortOrder()) {
689 case ASCENDING:
690 sortFields[i] = new SortField(orderHint.getPropertyName(), type, true);
691 break;
692 case DESCENDING:
693 default:
694 sortFields[i] = new SortField(orderHint.getPropertyName(), type, false);
695
696 }
697 }
698 sort.setSort(sortFields);
699 fullTextQuery.setSort(sort);
700
701 }
702 }
703
704 @Override
705 public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints) {
706 return list(limit,start,orderHints,null);
707 }
708
709 @Override
710 public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
711 Criteria criteria = getSession().createCriteria(type);
712 if(limit != null) {
713 criteria.setFirstResult(start);
714 criteria.setMaxResults(limit);
715 }
716
717 addOrder(criteria,orderHints);
718 @SuppressWarnings("unchecked")
719 List<T> results = criteria.list();
720
721 defaultBeanInitializer.initializeAll(results, propertyPaths);
722 return results;
723 }
724
725 @Override
726 public <S extends T> List<S> list(Class<S> clazz, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
727 Criteria criteria = null;
728 if(clazz == null) {
729 criteria = getSession().createCriteria(type);
730 } else {
731 criteria = getSession().createCriteria(clazz);
732 }
733
734 if(limit != null) {
735 if(start != null) {
736 criteria.setFirstResult(start);
737 } else {
738 criteria.setFirstResult(0);
739 }
740 criteria.setMaxResults(limit);
741 }
742
743 addOrder(criteria,orderHints);
744
745 @SuppressWarnings("unchecked")
746 List<S> results = criteria.list();
747
748 defaultBeanInitializer.initializeAll(results, propertyPaths);
749 return results;
750 }
751
752
753 public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start, List<OrderHint> orderHints) {
754 return list(type,limit,start,orderHints,null);
755 }
756
757 @Override
758 public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start) {
759 return list(type,limit,start,null,null);
760 }
761
762 @Override
763 public List<T> rows(String tableName, int limit, int start) {
764 Query query = getSession().createQuery("from " + tableName + " order by uuid");
765 query.setFirstResult(start);
766 query.setMaxResults(limit);
767 @SuppressWarnings("unchecked")
768 List<T> result = query.list();
769 return result;
770 }
771
772 @Override
773 public Class<T> getType() {
774 return type;
775 }
776
777 protected void setPagingParameter(Query query, Integer pageSize, Integer pageNumber){
778 if(pageSize != null) {
779 query.setMaxResults(pageSize);
780 if(pageNumber != null) {
781 query.setFirstResult(pageNumber * pageSize);
782 } else {
783 query.setFirstResult(0);
784 }
785 }
786 }
787
788 protected void setPagingParameter(AuditQuery query, Integer pageSize, Integer pageNumber){
789 if(pageSize != null) {
790 query.setMaxResults(pageSize);
791 if(pageNumber != null) {
792 query.setFirstResult(pageNumber * pageSize);
793 } else {
794 query.setFirstResult(0);
795 }
796 }
797 }
798
799 @Override
800 public int count(T example, Set<String> includeProperties) {
801 Criteria criteria = getSession().createCriteria(example.getClass());
802 addExample(criteria,example,includeProperties);
803
804 criteria.setProjection(Projections.rowCount());
805 return ((Number)criteria.uniqueResult()).intValue();
806 }
807
808 protected void addExample(Criteria criteria, T example, Set<String> includeProperties) {
809 if(includeProperties != null && !includeProperties.isEmpty()) {
810 criteria.add(Example.create(example).setPropertySelector(new PropertySelectorImpl(includeProperties)));
811 ClassMetadata classMetadata = getSession().getSessionFactory().getClassMetadata(example.getClass());
812 for(String property : includeProperties) {
813 Type type = classMetadata.getPropertyType(property);
814 if(type.isEntityType()) {
815 try {
816 Field field = ReflectionUtils.findField(example.getClass(), property);
817 field.setAccessible(true);
818 Object value = field.get(example);
819 if(value != null) {
820 criteria.add(Restrictions.eq(property,value));
821 } else {
822 criteria.add(Restrictions.isNull(property));
823 }
824 } catch (SecurityException se) {
825 throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, se);
826 } catch (HibernateException he) {
827 throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, he);
828 } catch (IllegalArgumentException iae) {
829 throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, iae);
830 } catch (IllegalAccessException ie) {
831 throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, ie);
832 }
833
834 }
835 }
836 } else {
837 criteria.add(Example.create(example));
838 }
839 }
840
841
842 protected int countByParam(Class<? extends T> clazz, String param, String queryString, MatchMode matchmode, List<Criterion> criterion) {
843 Criteria criteria = null;
844
845 if(clazz == null) {
846 criteria = getSession().createCriteria(type);
847 } else {
848 criteria = getSession().createCriteria(clazz);
849 }
850
851 if (queryString != null) {
852 if(matchmode == null) {
853 criteria.add(Restrictions.ilike(param, queryString));
854 } else if(matchmode == MatchMode.BEGINNING) {
855 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.START));
856 } else if(matchmode == MatchMode.END) {
857 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.END));
858 } else if(matchmode == MatchMode.EXACT) {
859 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.EXACT));
860 } else {
861 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.ANYWHERE));
862 }
863 }
864
865 addCriteria(criteria, criterion);
866
867 criteria.setProjection(Projections.rowCount());
868
869 // List<T> result = criteria.list();
870 return ((Number)criteria.uniqueResult()).intValue();
871 }
872
873
874 @Override
875 public List<T> list(T example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
876 Criteria criteria = getSession().createCriteria(example.getClass());
877 addExample(criteria,example,includeProperties);
878
879 if(limit != null) {
880 if(start != null) {
881 criteria.setFirstResult(start);
882 } else {
883 criteria.setFirstResult(0);
884 }
885 criteria.setMaxResults(limit);
886 }
887
888 addOrder(criteria,orderHints);
889
890 @SuppressWarnings("unchecked")
891 List<T> results = criteria.list();
892 defaultBeanInitializer.initializeAll(results, propertyPaths);
893 return results;
894 }
895
896 private class PropertySelectorImpl implements PropertySelector {
897
898 private final Set<String> includeProperties;
899 /**
900 *
901 */
902 private static final long serialVersionUID = -3175311800911570546L;
903
904 public PropertySelectorImpl(Set<String> includeProperties) {
905 this.includeProperties = includeProperties;
906 }
907
908 @Override
909 public boolean include(Object propertyValue, String propertyName, Type type) {
910 if(includeProperties.contains(propertyName)) {
911 return true;
912 } else {
913 return false;
914 }
915 }
916
917 }
918 }
919