Project

General

Profile

Download (32.7 KB) Statistics
| Branch: | Tag: | Revision:
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.Iterator;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Set;
20
import java.util.UUID;
21

    
22
import org.apache.log4j.Logger;
23
import org.apache.lucene.search.Sort;
24
import org.apache.lucene.search.SortField;
25
import org.hibernate.Criteria;
26
import org.hibernate.FlushMode;
27
import org.hibernate.HibernateException;
28
import org.hibernate.LockOptions;
29
import org.hibernate.NonUniqueObjectException;
30
import org.hibernate.Query;
31
import org.hibernate.Session;
32
import org.hibernate.criterion.Criterion;
33
import org.hibernate.criterion.DetachedCriteria;
34
import org.hibernate.criterion.Example;
35
import org.hibernate.criterion.Example.PropertySelector;
36
import org.hibernate.criterion.Order;
37
import org.hibernate.criterion.ProjectionList;
38
import org.hibernate.criterion.Projections;
39
import org.hibernate.criterion.Restrictions;
40
import org.hibernate.envers.query.AuditQuery;
41
import org.hibernate.metadata.ClassMetadata;
42
import org.hibernate.search.FullTextQuery;
43
import org.hibernate.type.Type;
44
import org.joda.time.DateTime;
45
import org.springframework.beans.factory.annotation.Autowired;
46
import org.springframework.dao.DataAccessException;
47
import org.springframework.dao.InvalidDataAccessApiUsageException;
48
import org.springframework.security.core.Authentication;
49
import org.springframework.security.core.context.SecurityContextHolder;
50
import org.springframework.stereotype.Repository;
51
import org.springframework.util.ReflectionUtils;
52

    
53
import eu.etaxonomy.cdm.model.common.CdmBase;
54
import eu.etaxonomy.cdm.model.common.User;
55
import eu.etaxonomy.cdm.model.common.VersionableEntity;
56
import eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao;
57
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
58
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
59
import eu.etaxonomy.cdm.persistence.hibernate.PostMergeEntityListener;
60
import eu.etaxonomy.cdm.persistence.hibernate.replace.ReferringObjectMetadata;
61
import eu.etaxonomy.cdm.persistence.hibernate.replace.ReferringObjectMetadataFactory;
62
import eu.etaxonomy.cdm.persistence.query.Grouping;
63
import eu.etaxonomy.cdm.persistence.query.MatchMode;
64
import eu.etaxonomy.cdm.persistence.query.OrderHint;
65

    
66

    
67
/**
68
 * @author a.mueller
69
 * FIXME CdmEntityDaoBase is abstract, can it be annotated with @Repository?
70
 */
71
@Repository
72
public abstract class CdmEntityDaoBase<T extends CdmBase> extends DaoBase implements ICdmEntityDao<T> {
73
    private static final Logger logger = Logger.getLogger(CdmEntityDaoBase.class);
74

    
75
    protected int flushAfterNo = 1000; //large numbers may cause synchronisation errors when commiting the session !!
76

    
77
    protected Class<T> type;
78

    
79
//    protected Version version = Configuration.luceneVersion;
80

    
81
    @Autowired
82
//	@Qualifier("defaultBeanInitializer")
83
    protected IBeanInitializer defaultBeanInitializer;
84

    
85
    public void setDefaultBeanInitializer(IBeanInitializer defaultBeanInitializer) {
86
        this.defaultBeanInitializer = defaultBeanInitializer;
87
    }
88

    
89
    @Autowired
90
    private ReferringObjectMetadataFactory referringObjectMetadataFactory;
91

    
92

    
93
    public CdmEntityDaoBase(Class<T> type){
94
        this.type = type;
95
        logger.debug("Creating DAO of type [" + type.getSimpleName() + "]");
96
    }
97

    
98
    @Override
99
    public void lock(T t, LockOptions lockOptions) {
100
        getSession().buildLockRequest(lockOptions).lock(t);
101
    }
102

    
103
    @Override
104
    public void refresh(T t, LockOptions lockOptions, List<String> propertyPaths) {
105
        getSession().refresh(t, lockOptions);
106
        defaultBeanInitializer.initialize(t, propertyPaths);
107
    }
108

    
109
    //TODO this method should be moved to a concrete class (not typed)
110
    public UUID saveCdmObj(CdmBase cdmObj) throws DataAccessException  {
111
        getSession().saveOrUpdate(cdmObj);
112
        return cdmObj.getUuid();
113
    }
114

    
115
    //TODO: Replace saveCdmObj() by saveCdmObject_
116
    private UUID saveCdmObject_(T cdmObj){
117
        getSession().saveOrUpdate(cdmObj);
118
        return cdmObj.getUuid();
119
    }
120

    
121
    //TODO: Use everywhere CdmEntityDaoBase.saveAll() instead of ServiceBase.saveCdmObjectAll()?
122
    //TODO: why does this use saveCdmObject_ which actually savesOrUpdateds data ?
123
    @Override
124
    public Map<UUID, T> saveAll(Collection<T> cdmObjCollection){
125
        int types = cdmObjCollection.getClass().getTypeParameters().length;
126
        if (types > 0){
127
            if (logger.isDebugEnabled()){logger.debug("ClassType: + " + cdmObjCollection.getClass().getTypeParameters()[0]);}
128
        }
129

    
130
        Map<UUID, T> resultMap = new HashMap<UUID, T>();
131
        Iterator<T> iterator = cdmObjCollection.iterator();
132
        int i = 0;
133
        while(iterator.hasNext()){
134
            if ( ( (i % 2000) == 0) && (i > 0)   ){logger.debug("Saved " + i + " objects" );}
135
            T cdmObj = iterator.next();
136
            UUID uuid = saveCdmObject_(cdmObj);
137
            if (logger.isDebugEnabled()){logger.debug("Save cdmObj: " + (cdmObj == null? null: cdmObj.toString()));}
138
            resultMap.put(uuid, cdmObj);
139
            i++;
140
            if ( (i % flushAfterNo) == 0){
141
                try{
142
                    if (logger.isDebugEnabled()){logger.debug("flush");}
143
                    flush();
144
                }catch(Exception e){
145
                    logger.error("An exception occurred when trying to flush data");
146
                    e.printStackTrace();
147
                    throw new RuntimeException(e);
148
                }
149
            }
150
        }
151

    
152
        if ( logger.isInfoEnabled() ){logger.info("Saved " + i + " objects" );}
153
        return resultMap;
154
    }
155

    
156
    private UUID saveOrUpdateCdmObject(T cdmObj){
157
        getSession().saveOrUpdate(cdmObj);
158
        return cdmObj.getUuid();
159
    }
160

    
161
    @Override
162
    public Map<UUID, T> saveOrUpdateAll(Collection<T> cdmObjCollection){
163
        int types = cdmObjCollection.getClass().getTypeParameters().length;
164
        if (types > 0){
165
            if (logger.isDebugEnabled()){logger.debug("ClassType: + " + cdmObjCollection.getClass().getTypeParameters()[0]);}
166
        }
167

    
168
        Map<UUID, T> resultMap = new HashMap<UUID, T>();
169
        Iterator<T> iterator = cdmObjCollection.iterator();
170
        int i = 0;
171
        while(iterator.hasNext()){
172
            if ( ( (i % 2000) == 0) && (i > 0)   ){logger.debug("Saved " + i + " objects" );}
173
            T cdmObj = iterator.next();
174
            UUID uuid = saveOrUpdateCdmObject(cdmObj);
175
            if (logger.isDebugEnabled()){logger.debug("Save cdmObj: " + (cdmObj == null? null: cdmObj.toString()));}
176
            resultMap.put(uuid, cdmObj);
177
            i++;
178
            if ( (i % flushAfterNo) == 0){
179
                try{
180
                    if (logger.isDebugEnabled()){logger.debug("flush");}
181
                    flush();
182
                }catch(Exception e){
183
                    logger.error("An exception occurred when trying to flush data");
184
                    e.printStackTrace();
185
                    throw new RuntimeException(e);
186
                }
187
            }
188
        }
189

    
190
        if ( logger.isInfoEnabled() ){logger.info("Saved " + i + " objects" );}
191
        return resultMap;
192
    }
193

    
194

    
195

    
196

    
197
    @Override
198
    public T replace(T x, T y) {
199
        if(x.equals(y)) {
200
            return y;
201
        }
202

    
203
        Class<?> commonClass = x.getClass();
204
        if(y != null) {
205
            while(!commonClass.isAssignableFrom(y.getClass())) {
206
                if(commonClass.equals(type)) {
207
                    throw new RuntimeException();
208
                }
209
                commonClass = commonClass.getSuperclass();
210
            }
211
        }
212

    
213
        getSession().merge(x);
214

    
215
        Set<ReferringObjectMetadata> referringObjectMetas = referringObjectMetadataFactory.get(x.getClass());
216

    
217
        for(ReferringObjectMetadata referringObjectMetadata : referringObjectMetas) {
218

    
219
          List<CdmBase> referringObjects = referringObjectMetadata.getReferringObjects(x, getSession());
220

    
221
          for(CdmBase referringObject : referringObjects) {
222
            try {
223
                referringObjectMetadata.replace(referringObject,x,y);
224
                getSession().update(referringObject);
225

    
226
            } catch (IllegalArgumentException e) {
227
                throw new RuntimeException(e.getMessage(),e);
228
            } catch (IllegalAccessException e) {
229
                throw new RuntimeException(e.getMessage(),e);
230
            }
231
          }
232
        }
233
        return y;
234
    }
235

    
236
    @Override
237
    public Session getSession() throws DataAccessException {
238
        return super.getSession();
239
    }
240

    
241
    @Override
242
    public void clear() throws DataAccessException {
243
        Session session = getSession();
244
        session.clear();
245
        if (logger.isDebugEnabled()){logger.debug("dao clear end");}
246
    }
247

    
248
    @Override
249
    public MergeResult<T> merge(T transientObject, boolean returnTransientEntity) throws DataAccessException {
250
        Session session = getSession();
251
        PostMergeEntityListener.addSession(session);
252
        MergeResult<T> result = null;
253
        try {
254
            @SuppressWarnings("unchecked")
255
            T persistentObject = (T)session.merge(transientObject);
256
            if (logger.isDebugEnabled()){logger.debug("dao merge end");}
257

    
258
            if(returnTransientEntity) {
259
                if(transientObject != null && persistentObject != null) {
260
                    transientObject.setId(persistentObject.getId());
261
                }
262
                result = new MergeResult(transientObject, PostMergeEntityListener.getNewEntities(session));
263
            } else {
264
                result = new MergeResult(persistentObject, null);
265
            }
266
            return result;
267
        } finally {
268
            PostMergeEntityListener.removeSession(session);
269
        }
270
    }
271

    
272
    @Override
273
    public T merge(T transientObject) throws DataAccessException {
274
        Session session = getSession();
275
        @SuppressWarnings("unchecked")
276
		T persistentObject = (T)session.merge(transientObject);
277
        if (logger.isDebugEnabled()){logger.debug("dao merge end");}
278
        return persistentObject;
279
    }
280

    
281
    @Override
282
    public UUID saveOrUpdate(T transientObject) throws DataAccessException  {
283
        if (transientObject == null){
284
        	logger.warn("Object to save should not be null. NOP");
285
        	return null;
286
        }
287
    	try {
288
            if (logger.isDebugEnabled()){logger.debug("dao saveOrUpdate start...");}
289
            if (logger.isDebugEnabled()){logger.debug("transientObject(" + transientObject.getClass().getSimpleName() + ") ID:" + transientObject.getId() + ", UUID: " + transientObject.getUuid()) ;}
290
            Session session = getSession();
291
            if(transientObject.getId() != 0 && VersionableEntity.class.isAssignableFrom(transientObject.getClass())) {
292
                VersionableEntity versionableEntity = (VersionableEntity)transientObject;
293
                versionableEntity.setUpdated(new DateTime());
294
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
295
                if(authentication != null && authentication.getPrincipal() != null && authentication.getPrincipal() instanceof User) {
296
                  User user = (User)authentication.getPrincipal();
297
                  versionableEntity.setUpdatedBy(user);
298
                }
299
            }
300
            session.saveOrUpdate(transientObject);
301
            if (logger.isDebugEnabled()){logger.debug("dao saveOrUpdate end");}
302
            return transientObject.getUuid();
303
        } catch (NonUniqueObjectException e) {
304
            logger.error("Error in CdmEntityDaoBase.saveOrUpdate(obj)");
305
            logger.error(e.getIdentifier());
306
            logger.error(e.getEntityName());
307
            logger.error(e.getMessage());
308

    
309
            e.printStackTrace();
310
            throw e;
311
        } catch (HibernateException e) {
312

    
313
            e.printStackTrace();
314
            throw e;
315
        }
316
    }
317

    
318
    @Override
319
    public T save(T newInstance) throws DataAccessException {
320
        if (newInstance == null){
321
        	logger.warn("Object to save should not be null. NOP");
322
        	return null;
323
        }
324
    	getSession().save(newInstance);
325
        return newInstance;
326
    }
327

    
328
    @Override
329
    public UUID update(T transientObject) throws DataAccessException {
330
        if (transientObject == null){
331
        	logger.warn("Object to update should not be null. NOP");
332
        	return null;
333
        }
334
    	getSession().update(transientObject);
335
        return transientObject.getUuid();
336
    }
337

    
338
    @Override
339
    public UUID refresh(T persistentObject) throws DataAccessException {
340
        getSession().refresh(persistentObject);
341
        return persistentObject.getUuid();
342
    }
343

    
344
    @Override
345
    public UUID delete(T persistentObject) throws DataAccessException {
346
        if (persistentObject == null){
347
            logger.warn(type.getName() + " was 'null'");
348
            return null;
349
        }
350

    
351
        // Merge the object in if it is detached
352
        //
353
        // I think this is preferable to catching lazy initialization errors
354
        // as that solution only swallows and hides the exception, but doesn't
355
        // actually solve it.
356
       persistentObject = (T) getSession().merge(persistentObject);
357
        getSession().delete(persistentObject);
358
        return persistentObject.getUuid();
359
    }
360

    
361
	@Override
362
    public T findById(int id) throws DataAccessException {
363
        return getSession().get(type, id);
364
    }
365

    
366

    
367
    @Override
368
    public T findByUuid(UUID uuid) throws DataAccessException{
369
        Session session = getSession();
370
        Criteria crit = session.createCriteria(type);
371
        crit.add(Restrictions.eq("uuid", uuid));
372
        crit.addOrder(Order.desc("created"));
373
        @SuppressWarnings("unchecked")
374
		List<T> results = crit.list();
375
        if (results.isEmpty()){
376
            return null;
377
        }else{
378
            if(results.size() > 1){
379
                logger.error("findByUuid() delivers more than one result for UUID: " + uuid);
380
            }
381
            return results.get(0);
382
        }
383
    }
384

    
385
    @Override
386
    public T findByUuidWithoutFlush(UUID uuid) throws DataAccessException{
387
    	Session session = getSession();
388
    	FlushMode currentFlushMode = session.getFlushMode();
389
    	try {
390
    		// set flush mode to manual so that the session does not flush
391
    		// when before performing the query
392
    		session.setFlushMode(FlushMode.MANUAL);
393
    		Criteria crit = session.createCriteria(type);
394
    		crit.add(Restrictions.eq("uuid", uuid));
395
    		crit.addOrder(Order.desc("created"));
396
    		@SuppressWarnings("unchecked")
397
			List<T> results = crit.list();
398
    		if (results.isEmpty()){
399
    			return null;
400
    		}else{
401
    			if(results.size() > 1){
402
    				logger.error("findByUuid() delivers more than one result for UUID: " + uuid);
403
    			}
404
    			return results.get(0);
405
    		}
406
    	} finally {
407
    		// set back the session flush mode
408
    		if(currentFlushMode != null) {
409
    			session.setFlushMode(currentFlushMode);
410
    		}
411
    	}
412
    }
413

    
414
    @Override
415
    public List<T> loadList(Collection<Integer> ids,  List<String> propertyPaths) throws DataAccessException {
416

    
417
        if (ids.isEmpty()) {
418
            return new ArrayList<T>(0);
419
        }
420

    
421
        Criteria criteria = prepareList(ids, null, null, null, "id");
422

    
423
        if (logger.isDebugEnabled()){logger.debug(criteria.toString());}
424

    
425
         @SuppressWarnings("unchecked")
426
		List<T> result = criteria.list();
427
         defaultBeanInitializer.initializeAll(result, propertyPaths);
428
         return result;
429
     }
430

    
431

    
432
    @Override
433
    public List<T> list(Collection<UUID> uuids, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) throws DataAccessException {
434

    
435
        Criteria criteria = prepareList(uuids, pageSize, pageNumber, orderHints, "uuid");
436

    
437
        @SuppressWarnings("unchecked")
438
		List<T> result = criteria.list();
439
        defaultBeanInitializer.initializeAll(result, propertyPaths);
440
        return result;
441
    }
442

    
443
    /**
444
     * @param uuids
445
     * @param pageSize
446
     * @param pageNumber
447
     * @param orderHints
448
     * @param propertyName
449
     * @return
450
     */
451
    private Criteria prepareList(Collection<?> uuids, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, String propertyName) {
452
        Criteria criteria = getSession().createCriteria(type);
453
        criteria.add(Restrictions.in(propertyName, uuids));
454

    
455
        if(pageSize != null) {
456
            criteria.setMaxResults(pageSize);
457
            if(pageNumber != null) {
458
                criteria.setFirstResult(pageNumber * pageSize);
459
            } else {
460
                criteria.setFirstResult(0);
461
            }
462
        }
463

    
464
        if(orderHints == null) {
465
            orderHints = OrderHint.defaultOrderHintsFor(type);
466
        }
467
        addOrder(criteria, orderHints);
468
        return criteria;
469
    }
470

    
471

    
472
    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) {
473
        Criteria criteria = null;
474

    
475
        if(clazz == null) {
476
            criteria = getSession().createCriteria(type);
477
        } else {
478
            criteria = getSession().createCriteria(clazz);
479
        }
480

    
481
        if (queryString != null) {
482
            if(matchmode == null) {
483
                criteria.add(Restrictions.ilike(param, queryString));
484
            } else if(matchmode == MatchMode.BEGINNING) {
485
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.START));
486
            } else if(matchmode == MatchMode.END) {
487
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.END));
488
            } else if(matchmode == MatchMode.EXACT) {
489
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.EXACT));
490
            } else {
491
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.ANYWHERE));
492
            }
493
        }
494

    
495
        addCriteria(criteria, criterion);
496

    
497
        if(pageSize != null) {
498
            criteria.setMaxResults(pageSize);
499
            if(pageNumber != null) {
500
                criteria.setFirstResult(pageNumber * pageSize);
501
            } else {
502
                criteria.setFirstResult(0);
503
            }
504
        }
505

    
506
        addOrder(criteria, orderHints);
507

    
508
        @SuppressWarnings("unchecked")
509
		List<T> result = criteria.list();
510
        defaultBeanInitializer.initializeAll(result, propertyPaths);
511
        return result;
512
    }
513

    
514
    @Override
515
    public T load(UUID uuid) {
516
        T bean = findByUuid(uuid);
517
        if(bean == null){
518
            return null;
519
        }
520
        defaultBeanInitializer.load(bean);
521

    
522
        return bean;
523
    }
524

    
525
    @Override
526
    public T load(int id, List<String> propertyPaths){
527
        T bean = findById(id);
528
        if(bean == null){
529
            return bean;
530
        }
531
        defaultBeanInitializer.initialize(bean, propertyPaths);
532

    
533
        return bean;
534
    }
535

    
536
    @Override
537
    public T load(UUID uuid, List<String> propertyPaths){
538
        T bean = findByUuid(uuid);
539
        if(bean == null){
540
            return bean;
541
        }
542
        defaultBeanInitializer.initialize(bean, propertyPaths);
543

    
544
        return bean;
545
    }
546

    
547
    @Override
548
    public Boolean exists(UUID uuid) {
549
        if (findByUuid(uuid)==null){
550
            return false;
551
        }
552
        return true;
553
    }
554

    
555
    @Override
556
    public int count() {
557
        return count(type);
558
    }
559

    
560
    @Override
561
    public int count(Class<? extends T> clazz) {
562
        Session session = getSession();
563
        Criteria criteria = null;
564
        if(clazz == null) {
565
            criteria = session.createCriteria(type);
566
        } else {
567
            criteria = session.createCriteria(clazz);
568
        }
569
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
570

    
571
        //since hibernate 4 (or so) uniqueResult returns Long, not Integer, therefore needs
572
        //to be casted. Think about returning long rather then int!
573
        return ((Number) criteria.uniqueResult()).intValue();
574
    }
575

    
576
    @Override
577
    public List<T> list(Integer limit, Integer start) {
578
        return list(limit, start, null);
579
    }
580

    
581
    @Override
582
    public List<Object[]> group(Class<? extends T> clazz,Integer limit, Integer start, List<Grouping> groups, List<String> propertyPaths) {
583

    
584
        Criteria criteria = null;
585
        if(clazz == null){
586
            criteria = getSession().createCriteria(type);
587
        } else {
588
            criteria = getSession().createCriteria(clazz);
589
        }
590

    
591
        addGroups(criteria,groups);
592

    
593
        if(limit != null) {
594
            criteria.setFirstResult(start);
595
            criteria.setMaxResults(limit);
596
        }
597

    
598
        @SuppressWarnings("unchecked")
599
		List<Object[]> result = criteria.list();
600

    
601
        if(propertyPaths != null && !propertyPaths.isEmpty()) {
602
          for(Object[] objects : result) {
603
            defaultBeanInitializer.initialize(objects[0], propertyPaths);
604
          }
605
        }
606

    
607
        return result;
608
    }
609

    
610
    protected void countGroups(DetachedCriteria criteria,List<Grouping> groups) {
611
        if(groups != null){
612

    
613

    
614
            Map<String,String> aliases = new HashMap<String,String>();
615

    
616
            for(Grouping grouping : groups) {
617
                if(grouping.getAssociatedObj() != null) {
618
                    String alias = null;
619
                    if((alias = aliases.get(grouping.getAssociatedObj())) == null) {
620
                        alias = grouping.getAssociatedObjectAlias();
621
                        aliases.put(grouping.getAssociatedObj(), alias);
622
                        criteria.createAlias(grouping.getAssociatedObj(),alias);
623
                    }
624
                }
625
            }
626

    
627
            ProjectionList projectionList = Projections.projectionList();
628

    
629
            for(Grouping grouping : groups) {
630
                grouping.addProjection(projectionList);
631
            }
632
            criteria.setProjection(projectionList);
633
        }
634
    }
635

    
636
    protected void addGroups(Criteria criteria,List<Grouping> groups) {
637
        if(groups != null){
638

    
639

    
640
            Map<String,String> aliases = new HashMap<String,String>();
641

    
642
            for(Grouping grouping : groups) {
643
                if(grouping.getAssociatedObj() != null) {
644
                    String alias = null;
645
                    if((alias = aliases.get(grouping.getAssociatedObj())) == null) {
646
                        alias = grouping.getAssociatedObjectAlias();
647
                        aliases.put(grouping.getAssociatedObj(), alias);
648
                        criteria.createAlias(grouping.getAssociatedObj(),alias);
649
                    }
650
                }
651
            }
652

    
653
            ProjectionList projectionList = Projections.projectionList();
654

    
655
            for(Grouping grouping : groups) {
656
                grouping.addProjection(projectionList);
657
            }
658
            criteria.setProjection(projectionList);
659

    
660
            for(Grouping grouping : groups) {
661
                grouping.addOrder(criteria);
662

    
663
            }
664
        }
665
    }
666

    
667
    protected void addCriteria(Criteria criteria, List<Criterion> criterion) {
668
        if(criterion != null) {
669
            for(Criterion c : criterion) {
670
                criteria.add(c);
671
            }
672
        }
673

    
674
    }
675

    
676
    protected void addOrder(FullTextQuery fullTextQuery, List<OrderHint> orderHints) {
677
        //FIXME preliminary hardcoded type:
678
    	SortField.Type type = SortField.Type.STRING;
679

    
680
    	if(orderHints != null && !orderHints.isEmpty()) {
681
            org.apache.lucene.search.Sort sort = new Sort();
682
            SortField[] sortFields = new SortField[orderHints.size()];
683
            for(int i = 0; i < orderHints.size(); i++) {
684
                OrderHint orderHint = orderHints.get(i);
685
                switch(orderHint.getSortOrder()) {
686
                case ASCENDING:
687
                    sortFields[i] = new SortField(orderHint.getPropertyName(), type, true);
688
                    break;
689
                case DESCENDING:
690
                default:
691
                    sortFields[i] = new SortField(orderHint.getPropertyName(), type, false);
692

    
693
                }
694
            }
695
            sort.setSort(sortFields);
696
            fullTextQuery.setSort(sort);
697

    
698
        }
699
    }
700

    
701
    @Override
702
    public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints) {
703
        return list(limit,start,orderHints,null);
704
    }
705

    
706
    @Override
707
    public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
708
        Criteria criteria = getSession().createCriteria(type);
709
        if(limit != null) {
710
            criteria.setFirstResult(start);
711
            criteria.setMaxResults(limit);
712
        }
713

    
714
        addOrder(criteria,orderHints);
715
        @SuppressWarnings("unchecked")
716
		List<T> results = criteria.list();
717

    
718
        defaultBeanInitializer.initializeAll(results, propertyPaths);
719
        return results;
720
    }
721

    
722
    @Override
723
    public <S extends T> List<S> list(Class<S> clazz, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
724
        Criteria criteria = null;
725
        if(clazz == null) {
726
            criteria = getSession().createCriteria(type);
727
        } else {
728
            criteria = getSession().createCriteria(clazz);
729
        }
730

    
731
        if(limit != null) {
732
            if(start != null) {
733
                criteria.setFirstResult(start);
734
            } else {
735
                criteria.setFirstResult(0);
736
            }
737
            criteria.setMaxResults(limit);
738
        }
739

    
740
        addOrder(criteria,orderHints);
741

    
742
        @SuppressWarnings("unchecked")
743
		List<S> results = criteria.list();
744
        defaultBeanInitializer.initializeAll(results, propertyPaths);
745
        return results;
746
    }
747

    
748
    public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start, List<OrderHint> orderHints) {
749
        return list(type,limit,start,orderHints,null);
750
    }
751

    
752
    @Override
753
    public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start) {
754
        return list(type,limit,start,null,null);
755
    }
756

    
757
    @Override
758
    public List<T> rows(String tableName, int limit, int start) {
759
        Query query = getSession().createQuery("from " + tableName + " order by uuid");
760
        query.setFirstResult(start);
761
        query.setMaxResults(limit);
762
        @SuppressWarnings("unchecked")
763
		List<T> result = query.list();
764
        return result;
765
    }
766

    
767
    @Override
768
    public Class<T> getType() {
769
        return type;
770
    }
771

    
772
    protected void setPagingParameter(Query query, Integer pageSize, Integer pageNumber){
773
        if(pageSize != null) {
774
            query.setMaxResults(pageSize);
775
            if(pageNumber != null) {
776
                query.setFirstResult(pageNumber * pageSize);
777
            } else {
778
                query.setFirstResult(0);
779
            }
780
        }
781
    }
782

    
783
    protected void setPagingParameter(AuditQuery query, Integer pageSize, Integer pageNumber){
784
        if(pageSize != null) {
785
            query.setMaxResults(pageSize);
786
            if(pageNumber != null) {
787
                query.setFirstResult(pageNumber * pageSize);
788
            } else {
789
                query.setFirstResult(0);
790
            }
791
        }
792
    }
793

    
794
    @Override
795
    public int count(T example, Set<String> includeProperties) {
796
        Criteria criteria = getSession().createCriteria(example.getClass());
797
        addExample(criteria,example,includeProperties);
798

    
799
        criteria.setProjection(Projections.rowCount());
800
        return ((Number)criteria.uniqueResult()).intValue();
801
    }
802

    
803
    protected void addExample(Criteria criteria, T example, Set<String> includeProperties) {
804
        if(includeProperties != null && !includeProperties.isEmpty()) {
805
            criteria.add(Example.create(example).setPropertySelector(new PropertySelectorImpl(includeProperties)));
806
            ClassMetadata classMetadata = getSession().getSessionFactory().getClassMetadata(example.getClass());
807
            for(String property : includeProperties) {
808
                Type type  = classMetadata.getPropertyType(property);
809
                if(type.isEntityType()) {
810
                    try {
811
                        Field field = ReflectionUtils.findField(example.getClass(), property);
812
                        field.setAccessible(true);
813
                        Object value =  field.get(example);
814
                        if(value != null) {
815
                            criteria.add(Restrictions.eq(property,value));
816
                        } else {
817
                            criteria.add(Restrictions.isNull(property));
818
                        }
819
                    } catch (SecurityException se) {
820
                        throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, se);
821
                    } catch (HibernateException he) {
822
                        throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, he);
823
                    } catch (IllegalArgumentException iae) {
824
                        throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, iae);
825
                    } catch (IllegalAccessException ie) {
826
                        throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property, ie);
827
                    }
828

    
829
                }
830
            }
831
        } else {
832
            criteria.add(Example.create(example));
833
        }
834
    }
835

    
836

    
837
    protected int countByParam(Class<? extends T> clazz, String param, String queryString, MatchMode matchmode, List<Criterion> criterion) {
838
        Criteria criteria = null;
839

    
840
        if(clazz == null) {
841
            criteria = getSession().createCriteria(type);
842
        } else {
843
            criteria = getSession().createCriteria(clazz);
844
        }
845

    
846
        if (queryString != null) {
847
            if(matchmode == null) {
848
                criteria.add(Restrictions.ilike(param, queryString));
849
            } else if(matchmode == MatchMode.BEGINNING) {
850
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.START));
851
            } else if(matchmode == MatchMode.END) {
852
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.END));
853
            } else if(matchmode == MatchMode.EXACT) {
854
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.EXACT));
855
            } else {
856
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.ANYWHERE));
857
            }
858
        }
859

    
860
        addCriteria(criteria, criterion);
861

    
862
        criteria.setProjection(Projections.rowCount());
863

    
864
//        List<T> result = criteria.list();
865
        return ((Number)criteria.uniqueResult()).intValue();
866
    }
867

    
868

    
869
    @Override
870
    public List<T> list(T example, Set<String> includeProperties, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
871
        Criteria criteria = getSession().createCriteria(example.getClass());
872
        addExample(criteria,example,includeProperties);
873

    
874
        if(limit != null) {
875
            if(start != null) {
876
                criteria.setFirstResult(start);
877
            } else {
878
                criteria.setFirstResult(0);
879
            }
880
            criteria.setMaxResults(limit);
881
        }
882

    
883
        addOrder(criteria,orderHints);
884

    
885
        @SuppressWarnings("unchecked")
886
		List<T> results = criteria.list();
887
        defaultBeanInitializer.initializeAll(results, propertyPaths);
888
        return results;
889
    }
890

    
891
    private class PropertySelectorImpl implements PropertySelector {
892

    
893
        private final Set<String> includeProperties;
894
        /**
895
         *
896
         */
897
        private static final long serialVersionUID = -3175311800911570546L;
898

    
899
        public PropertySelectorImpl(Set<String> includeProperties) {
900
            this.includeProperties = includeProperties;
901
        }
902

    
903
        @Override
904
        public boolean include(Object propertyValue, String propertyName,	Type type) {
905
            if(includeProperties.contains(propertyName)) {
906
                return true;
907
            } else {
908
                return false;
909
            }
910
        }
911

    
912
    }
913
}
914

    
(3-3/23)