cleanup
[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 if (uuids == null || uuids.isEmpty()){
439 return new ArrayList<>();
440 }
441
442 Criteria criteria = prepareList(uuids, pageSize, pageNumber, orderHints, "uuid");
443
444 @SuppressWarnings("unchecked")
445 List<T> result = criteria.list();
446 defaultBeanInitializer.initializeAll(result, propertyPaths);
447 return result;
448 }
449
450 /**
451 * @param uuids
452 * @param pageSize
453 * @param pageNumber
454 * @param orderHints
455 * @param propertyName
456 * @return
457 */
458 private Criteria prepareList(Collection<?> uuids, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, String propertyName) {
459 Criteria criteria = getSession().createCriteria(type);
460 criteria.add(Restrictions.in(propertyName, uuids));
461
462 if(pageSize != null) {
463 criteria.setMaxResults(pageSize);
464 if(pageNumber != null) {
465 criteria.setFirstResult(pageNumber * pageSize);
466 } else {
467 criteria.setFirstResult(0);
468 }
469 }
470
471 if(orderHints == null) {
472 orderHints = OrderHint.defaultOrderHintsFor(type);
473 }
474 addOrder(criteria, orderHints);
475 return criteria;
476 }
477
478
479 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) {
480 Criteria criteria = null;
481
482 if(clazz == null) {
483 criteria = getSession().createCriteria(type);
484 } else {
485 criteria = getSession().createCriteria(clazz);
486 }
487
488 if (queryString != null) {
489 if(matchmode == null) {
490 criteria.add(Restrictions.ilike(param, queryString));
491 } else if(matchmode == MatchMode.BEGINNING) {
492 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.START));
493 } else if(matchmode == MatchMode.END) {
494 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.END));
495 } else if(matchmode == MatchMode.EXACT) {
496 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.EXACT));
497 } else {
498 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.ANYWHERE));
499 }
500 }
501
502 addCriteria(criteria, criterion);
503
504 if(pageSize != null) {
505 criteria.setMaxResults(pageSize);
506 if(pageNumber != null) {
507 criteria.setFirstResult(pageNumber * pageSize);
508 } else {
509 criteria.setFirstResult(0);
510 }
511 }
512
513 addOrder(criteria, orderHints);
514
515 @SuppressWarnings("unchecked")
516 List<T> result = criteria.list();
517 defaultBeanInitializer.initializeAll(result, propertyPaths);
518 return result;
519 }
520
521 @Override
522 public T load(UUID uuid) {
523 T bean = findByUuid(uuid);
524 if(bean == null){
525 return null;
526 }
527 defaultBeanInitializer.load(bean);
528
529 return bean;
530 }
531
532 @Override
533 public T load(int id, List<String> propertyPaths){
534 T bean = findById(id);
535 if(bean == null){
536 return bean;
537 }
538 defaultBeanInitializer.initialize(bean, propertyPaths);
539
540 return bean;
541 }
542
543 @Override
544 public T load(UUID uuid, List<String> propertyPaths){
545 T bean = findByUuid(uuid);
546 if(bean == null){
547 return bean;
548 }
549 defaultBeanInitializer.initialize(bean, propertyPaths);
550
551 return bean;
552 }
553
554 @Override
555 public Boolean exists(UUID uuid) {
556 if (findByUuid(uuid)==null){
557 return false;
558 }
559 return true;
560 }
561
562 @Override
563 public int count() {
564 return count(type);
565 }
566
567 @Override
568 public int count(Class<? extends T> clazz) {
569 Session session = getSession();
570 Criteria criteria = null;
571 if(clazz == null) {
572 criteria = session.createCriteria(type);
573 } else {
574 criteria = session.createCriteria(clazz);
575 }
576 criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
577
578 //since hibernate 4 (or so) uniqueResult returns Long, not Integer, therefore needs
579 //to be casted. Think about returning long rather then int!
580 return ((Number) criteria.uniqueResult()).intValue();
581 }
582
583 @Override
584 public List<T> list(Integer limit, Integer start) {
585 return list(limit, start, null);
586 }
587
588 @Override
589 public List<Object[]> group(Class<? extends T> clazz,Integer limit, Integer start, List<Grouping> groups, List<String> propertyPaths) {
590
591 Criteria criteria = null;
592 if(clazz == null){
593 criteria = getSession().createCriteria(type);
594 } else {
595 criteria = getSession().createCriteria(clazz);
596 }
597
598 addGroups(criteria,groups);
599
600 if(limit != null) {
601 criteria.setFirstResult(start);
602 criteria.setMaxResults(limit);
603 }
604
605 @SuppressWarnings("unchecked")
606 List<Object[]> result = criteria.list();
607
608 if(propertyPaths != null && !propertyPaths.isEmpty()) {
609 for(Object[] objects : result) {
610 defaultBeanInitializer.initialize(objects[0], propertyPaths);
611 }
612 }
613
614 return result;
615 }
616
617 protected void countGroups(DetachedCriteria criteria,List<Grouping> groups) {
618 if(groups != null){
619
620
621 Map<String,String> aliases = new HashMap<String,String>();
622
623 for(Grouping grouping : groups) {
624 if(grouping.getAssociatedObj() != null) {
625 String alias = null;
626 if((alias = aliases.get(grouping.getAssociatedObj())) == null) {
627 alias = grouping.getAssociatedObjectAlias();
628 aliases.put(grouping.getAssociatedObj(), alias);
629 criteria.createAlias(grouping.getAssociatedObj(),alias);
630 }
631 }
632 }
633
634 ProjectionList projectionList = Projections.projectionList();
635
636 for(Grouping grouping : groups) {
637 grouping.addProjection(projectionList);
638 }
639 criteria.setProjection(projectionList);
640 }
641 }
642
643 protected void addGroups(Criteria criteria,List<Grouping> groups) {
644 if(groups != null){
645
646
647 Map<String,String> aliases = new HashMap<String,String>();
648
649 for(Grouping grouping : groups) {
650 if(grouping.getAssociatedObj() != null) {
651 String alias = null;
652 if((alias = aliases.get(grouping.getAssociatedObj())) == null) {
653 alias = grouping.getAssociatedObjectAlias();
654 aliases.put(grouping.getAssociatedObj(), alias);
655 criteria.createAlias(grouping.getAssociatedObj(),alias);
656 }
657 }
658 }
659
660 ProjectionList projectionList = Projections.projectionList();
661
662 for(Grouping grouping : groups) {
663 grouping.addProjection(projectionList);
664 }
665 criteria.setProjection(projectionList);
666
667 for(Grouping grouping : groups) {
668 grouping.addOrder(criteria);
669
670 }
671 }
672 }
673
674 protected void addCriteria(Criteria criteria, List<Criterion> criterion) {
675 if(criterion != null) {
676 for(Criterion c : criterion) {
677 criteria.add(c);
678 }
679 }
680
681 }
682
683 protected void addOrder(FullTextQuery fullTextQuery, List<OrderHint> orderHints) {
684 //FIXME preliminary hardcoded type:
685 SortField.Type type = SortField.Type.STRING;
686
687 if(orderHints != null && !orderHints.isEmpty()) {
688 org.apache.lucene.search.Sort sort = new Sort();
689 SortField[] sortFields = new SortField[orderHints.size()];
690 for(int i = 0; i < orderHints.size(); i++) {
691 OrderHint orderHint = orderHints.get(i);
692 switch(orderHint.getSortOrder()) {
693 case ASCENDING:
694 sortFields[i] = new SortField(orderHint.getPropertyName(), type, true);
695 break;
696 case DESCENDING:
697 default:
698 sortFields[i] = new SortField(orderHint.getPropertyName(), type, false);
699
700 }
701 }
702 sort.setSort(sortFields);
703 fullTextQuery.setSort(sort);
704
705 }
706 }
707
708 @Override
709 public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints) {
710 return list(limit,start,orderHints,null);
711 }
712
713 @Override
714 public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
715 Criteria criteria = getSession().createCriteria(type);
716 if(limit != null) {
717 criteria.setFirstResult(start);
718 criteria.setMaxResults(limit);
719 }
720
721 addOrder(criteria,orderHints);
722 @SuppressWarnings("unchecked")
723 List<T> results = criteria.list();
724
725 defaultBeanInitializer.initializeAll(results, propertyPaths);
726 return results;
727 }
728
729 @Override
730 public <S extends T> List<S> list(Class<S> clazz, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
731 Criteria criteria = null;
732 if(clazz == null) {
733 criteria = getSession().createCriteria(type);
734 } else {
735 criteria = getSession().createCriteria(clazz);
736 }
737
738 if(limit != null) {
739 if(start != null) {
740 criteria.setFirstResult(start);
741 } else {
742 criteria.setFirstResult(0);
743 }
744 criteria.setMaxResults(limit);
745 }
746
747 addOrder(criteria, orderHints);
748
749 @SuppressWarnings("unchecked")
750 List<S> results = criteria.list();
751
752 defaultBeanInitializer.initializeAll(results, propertyPaths);
753 return results;
754 }
755
756
757 public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start, List<OrderHint> orderHints) {
758 return list(type,limit,start,orderHints,null);
759 }
760
761 @Override
762 public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start) {
763 return list(type,limit,start,null,null);
764 }
765
766 @Override
767 public List<T> rows(String tableName, int limit, int start) {
768 Query query = getSession().createQuery("from " + tableName + " order by uuid");
769 query.setFirstResult(start);
770 query.setMaxResults(limit);
771 @SuppressWarnings("unchecked")
772 List<T> result = query.list();
773 return result;
774 }
775
776 @Override
777 public Class<T> getType() {
778 return type;
779 }
780
781 protected void setPagingParameter(Query query, Integer pageSize, Integer pageNumber){
782 if(pageSize != null) {
783 query.setMaxResults(pageSize);
784 if(pageNumber != null) {
785 query.setFirstResult(pageNumber * pageSize);
786 } else {
787 query.setFirstResult(0);
788 }
789 }
790 }
791
792 protected void setPagingParameter(AuditQuery query, Integer pageSize, Integer pageNumber){
793 if(pageSize != null) {
794 query.setMaxResults(pageSize);
795 if(pageNumber != null) {
796 query.setFirstResult(pageNumber * pageSize);
797 } else {
798 query.setFirstResult(0);
799 }
800 }
801 }
802
803 @Override
804 public int count(T example, Set<String> includeProperties) {
805 Criteria criteria = getSession().createCriteria(example.getClass());
806 addExample(criteria,example,includeProperties);
807
808 criteria.setProjection(Projections.rowCount());
809 return ((Number)criteria.uniqueResult()).intValue();
810 }
811
812 protected void addExample(Criteria criteria, T example, Set<String> includeProperties) {
813 if(includeProperties != null && !includeProperties.isEmpty()) {
814 criteria.add(Example.create(example).setPropertySelector(new PropertySelectorImpl(includeProperties)));
815 ClassMetadata classMetadata = getSession().getSessionFactory().getClassMetadata(example.getClass());
816 for(String property : includeProperties) {
817 Type type = classMetadata.getPropertyType(property);
818 if(type.isEntityType()) {
819 try {
820 Field field = ReflectionUtils.findField(example.getClass(), property);
821 field.setAccessible(true);
822 Object value = field.get(example);
823 if(value != null) {
824 criteria.add(Restrictions.eq(property,value));
825 } else {
826 criteria.add(Restrictions.isNull(property));
827 }
828 } catch (SecurityException se) {
829 throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, se);
830 } catch (HibernateException he) {
831 throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, he);
832 } catch (IllegalArgumentException iae) {
833 throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, iae);
834 } catch (IllegalAccessException ie) {
835 throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, ie);
836 }
837
838 }
839 }
840 } else {
841 criteria.add(Example.create(example));
842 }
843 }
844
845
846 protected long countByParam(Class<? extends T> clazz, String param, String queryString, MatchMode matchmode, List<Criterion> criterion) {
847 Criteria criteria = null;
848
849 if(clazz == null) {
850 criteria = getSession().createCriteria(type);
851 } else {
852 criteria = getSession().createCriteria(clazz);
853 }
854
855 if (queryString != null) {
856 if(matchmode == null) {
857 criteria.add(Restrictions.ilike(param, queryString));
858 } else if(matchmode == MatchMode.BEGINNING) {
859 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.START));
860 } else if(matchmode == MatchMode.END) {
861 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.END));
862 } else if(matchmode == MatchMode.EXACT) {
863 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.EXACT));
864 } else {
865 criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.ANYWHERE));
866 }
867 }
868
869 addCriteria(criteria, criterion);
870
871 criteria.setProjection(Projections.rowCount());
872
873 return ((Number)criteria.uniqueResult()).longValue();
874 }
875
876
877 @Override
878 public List<T> list(T example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
879 Criteria criteria = getSession().createCriteria(example.getClass());
880 addExample(criteria,example,includeProperties);
881
882 if(limit != null) {
883 if(start != null) {
884 criteria.setFirstResult(start);
885 } else {
886 criteria.setFirstResult(0);
887 }
888 criteria.setMaxResults(limit);
889 }
890
891 addOrder(criteria,orderHints);
892
893 @SuppressWarnings("unchecked")
894 List<T> results = criteria.list();
895 defaultBeanInitializer.initializeAll(results, propertyPaths);
896 return results;
897 }
898
899 private class PropertySelectorImpl implements PropertySelector {
900
901 private final Set<String> includeProperties;
902 /**
903 *
904 */
905 private static final long serialVersionUID = -3175311800911570546L;
906
907 public PropertySelectorImpl(Set<String> includeProperties) {
908 this.includeProperties = includeProperties;
909 }
910
911 @Override
912 public boolean include(Object propertyValue, String propertyName, Type type) {
913 if(includeProperties.contains(propertyName)) {
914 return true;
915 } else {
916 return false;
917 }
918 }
919
920 }
921 }
922