Project

General

Profile

Download (49 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.EnumSet;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.Set;
22
import java.util.UUID;
23

    
24
import org.apache.log4j.Logger;
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.Disjunction;
35
import org.hibernate.criterion.Example;
36
import org.hibernate.criterion.Example.PropertySelector;
37
import org.hibernate.criterion.LogicalExpression;
38
import org.hibernate.criterion.Order;
39
import org.hibernate.criterion.ProjectionList;
40
import org.hibernate.criterion.Projections;
41
import org.hibernate.criterion.Restrictions;
42
import org.hibernate.criterion.Subqueries;
43
import org.hibernate.envers.AuditReader;
44
import org.hibernate.envers.AuditReaderFactory;
45
import org.hibernate.envers.query.AuditQuery;
46
import org.hibernate.metadata.ClassMetadata;
47
import org.hibernate.sql.JoinType;
48
import org.hibernate.type.Type;
49
import org.joda.time.DateTime;
50
import org.springframework.beans.factory.annotation.Autowired;
51
import org.springframework.dao.DataAccessException;
52
import org.springframework.dao.InvalidDataAccessApiUsageException;
53
import org.springframework.security.core.Authentication;
54
import org.springframework.security.core.context.SecurityContextHolder;
55
import org.springframework.stereotype.Repository;
56
import org.springframework.util.ReflectionUtils;
57

    
58
import eu.etaxonomy.cdm.model.common.CdmBase;
59
import eu.etaxonomy.cdm.model.common.IPublishable;
60
import eu.etaxonomy.cdm.model.common.VersionableEntity;
61
import eu.etaxonomy.cdm.model.permission.User;
62
import eu.etaxonomy.cdm.model.view.AuditEvent;
63
import eu.etaxonomy.cdm.persistence.dao.common.ICdmEntityDao;
64
import eu.etaxonomy.cdm.persistence.dao.common.Restriction;
65
import eu.etaxonomy.cdm.persistence.dao.common.Restriction.Operator;
66
import eu.etaxonomy.cdm.persistence.dao.initializer.IBeanInitializer;
67
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
68
import eu.etaxonomy.cdm.persistence.hibernate.PostMergeEntityListener;
69
import eu.etaxonomy.cdm.persistence.hibernate.replace.ReferringObjectMetadata;
70
import eu.etaxonomy.cdm.persistence.hibernate.replace.ReferringObjectMetadataFactory;
71
import eu.etaxonomy.cdm.persistence.query.Grouping;
72
import eu.etaxonomy.cdm.persistence.query.MatchMode;
73
import eu.etaxonomy.cdm.persistence.query.OrderHint;
74

    
75
/**
76
 * @author a.mueller FIXME CdmEntityDaoBase is abstract, can it be annotated
77
 *         with @Repository?
78
 */
79
@Repository
80
public abstract class CdmEntityDaoBase<T extends CdmBase>
81
        extends DaoBase
82
        implements ICdmEntityDao<T> {
83

    
84
    private static final Logger logger = Logger.getLogger(CdmEntityDaoBase.class);
85

    
86
    protected int flushAfterNo = 1000; // large numbers may cause
87
                                       // synchronisation errors when commiting
88
                                       // the session !!
89

    
90
    protected Class<T> type;
91

    
92
    @Autowired
93
    // @Qualifier("defaultBeanInitializer")
94
    protected IBeanInitializer defaultBeanInitializer;
95

    
96
    public void setDefaultBeanInitializer(IBeanInitializer defaultBeanInitializer) {
97
        this.defaultBeanInitializer = defaultBeanInitializer;
98
    }
99

    
100
    @Autowired
101
    private ReferringObjectMetadataFactory referringObjectMetadataFactory;
102

    
103
    protected static final EnumSet<Operator> LEFTOUTER_OPS = EnumSet.of(Operator.AND_NOT, Operator.OR, Operator.OR_NOT);
104

    
105
    public CdmEntityDaoBase(Class<T> type) {
106
        this.type = type;
107
        assert type != null;
108
        logger.debug("Creating DAO of type [" + type.getSimpleName() + "]");
109
    }
110

    
111
    @Override
112
    public void lock(T t, LockOptions lockOptions) {
113
        getSession().buildLockRequest(lockOptions).lock(t);
114
    }
115

    
116
    @Override
117
    public void refresh(T t, LockOptions lockOptions, List<String> propertyPaths) {
118
        getSession().refresh(t, lockOptions);
119
        defaultBeanInitializer.initialize(t, propertyPaths);
120
    }
121

    
122
    // TODO this method should be moved to a concrete class (not typed)
123
    public UUID saveCdmObj(CdmBase cdmObj) throws DataAccessException {
124
        getSession().saveOrUpdate(cdmObj);
125
        return cdmObj.getUuid();
126
    }
127

    
128
    // TODO: Replace saveCdmObj() by saveCdmObject_
129
    private UUID saveCdmObject_(T cdmObj) {
130
        getSession().saveOrUpdate(cdmObj);
131
        return cdmObj.getUuid();
132
    }
133

    
134
    // TODO: Use everywhere CdmEntityDaoBase.saveAll() instead of
135
    // ServiceBase.saveCdmObjectAll()?
136
    // TODO: why does this use saveCdmObject_ which actually savesOrUpdateds
137
    // data ?
138
    @Override
139
    public Map<UUID, T> saveAll(Collection<T> cdmObjCollection) {
140
        int types = cdmObjCollection.getClass().getTypeParameters().length;
141
        if (types > 0) {
142
            if (logger.isDebugEnabled()) {
143
                logger.debug("ClassType: + " + cdmObjCollection.getClass().getTypeParameters()[0]);
144
            }
145
        }
146

    
147
        Map<UUID, T> resultMap = new HashMap<>();
148
        Iterator<T> iterator = cdmObjCollection.iterator();
149
        int i = 0;
150
        while (iterator.hasNext()) {
151
            if (((i % 2000) == 0) && (i > 0)) {
152
                logger.debug("Saved " + i + " objects");
153
            }
154
            T cdmObj = iterator.next();
155
            UUID uuid = saveCdmObject_(cdmObj);
156
            if (logger.isDebugEnabled()) {
157
                logger.debug("Save cdmObj: " + (cdmObj == null ? null : cdmObj.toString()));
158
            }
159
            resultMap.put(uuid, cdmObj);
160
            i++;
161
            if ((i % flushAfterNo) == 0) {
162
                try {
163
                    if (logger.isDebugEnabled()) {
164
                        logger.debug("flush");
165
                    }
166
                    flush();
167
                } catch (Exception e) {
168
                    logger.error("An exception occurred when trying to flush data");
169
                    e.printStackTrace();
170
                    throw new RuntimeException(e);
171
                }
172
            }
173
        }
174

    
175
        if (logger.isInfoEnabled()) {
176
            logger.info("Saved " + i + " objects");
177
        }
178
        return resultMap;
179
    }
180

    
181
    private UUID saveOrUpdateCdmObject(T cdmObj) {
182
        getSession().saveOrUpdate(cdmObj);
183
        return cdmObj.getUuid();
184
    }
185

    
186
    @Override
187
    public Map<UUID, T> saveOrUpdateAll(Collection<T> cdmObjCollection) {
188
        int types = cdmObjCollection.getClass().getTypeParameters().length;
189
        if (types > 0) {
190
            if (logger.isDebugEnabled()) {
191
                logger.debug("ClassType: + " + cdmObjCollection.getClass().getTypeParameters()[0]);
192
            }
193
        }
194

    
195
        Map<UUID, T> resultMap = new HashMap<>();
196
        Iterator<T> iterator = cdmObjCollection.iterator();
197
        int i = 0;
198
        while (iterator.hasNext()) {
199
            if (((i % 2000) == 0) && (i > 0)) {
200
                logger.debug("Saved " + i + " objects");
201
            }
202
            T cdmObj = iterator.next();
203
            UUID uuid = saveOrUpdateCdmObject(cdmObj);
204
            if (logger.isDebugEnabled()) {
205
                logger.debug("Save cdmObj: " + (cdmObj == null ? null : cdmObj.toString()));
206
            }
207
            resultMap.put(uuid, cdmObj);
208
            i++;
209
            if ((i % flushAfterNo) == 0) {
210
                try {
211
                    if (logger.isDebugEnabled()) {
212
                        logger.debug("flush");
213
                    }
214
                    flush();
215
                } catch (Exception e) {
216
                    logger.error("An exception occurred when trying to flush data");
217
                    e.printStackTrace();
218
                    throw new RuntimeException(e);
219
                }
220
            }
221
        }
222

    
223
        if (logger.isInfoEnabled()) {
224
            logger.info("Saved " + i + " objects");
225
        }
226
        return resultMap;
227
    }
228

    
229
    @Override
230
    public T replace(T x, T y) {
231
        if (x.equals(y)) {
232
            return y;
233
        }
234

    
235
        Class<?> commonClass = x.getClass();
236
        if (y != null) {
237
            while (!commonClass.isAssignableFrom(y.getClass())) {
238
                if (commonClass.equals(type)) {
239
                    throw new RuntimeException();
240
                }
241
                commonClass = commonClass.getSuperclass();
242
            }
243
        }
244

    
245
        getSession().merge(x);
246

    
247
        Set<ReferringObjectMetadata> referringObjectMetas = referringObjectMetadataFactory.get(x.getClass());
248

    
249
        for (ReferringObjectMetadata referringObjectMetadata : referringObjectMetas) {
250

    
251
            List<CdmBase> referringObjects = referringObjectMetadata.getReferringObjects(x, getSession());
252

    
253
            for (CdmBase referringObject : referringObjects) {
254
                try {
255
                    referringObjectMetadata.replace(referringObject, x, y);
256
                    getSession().update(referringObject);
257

    
258
                } catch (IllegalArgumentException e) {
259
                    throw new RuntimeException(e.getMessage(), e);
260
                } catch (IllegalAccessException e) {
261
                    throw new RuntimeException(e.getMessage(), e);
262
                }
263
            }
264
        }
265
        return y;
266
    }
267

    
268
    @Override
269
    public Session getSession() throws DataAccessException {
270
        return super.getSession();
271
    }
272

    
273
    @Override
274
    public void clear() throws DataAccessException {
275
        Session session = getSession();
276
        session.clear();
277
        if (logger.isDebugEnabled()) {
278
            logger.debug("dao clear end");
279
        }
280
    }
281

    
282
    @Override
283
    public MergeResult<T> merge(T transientObject, boolean returnTransientEntity) throws DataAccessException {
284
        Session session = getSession();
285
        PostMergeEntityListener.addSession(session);
286
        MergeResult<T> result = null;
287
        try {
288
            @SuppressWarnings("unchecked")
289
            T persistentObject = (T) session.merge(transientObject);
290
            if (logger.isDebugEnabled()) {
291
                logger.debug("dao merge end");
292
            }
293

    
294
            if (returnTransientEntity) {
295
                if (transientObject != null && persistentObject != null) {
296
                    transientObject.setId(persistentObject.getId());
297
                }
298
                result = new MergeResult(transientObject, PostMergeEntityListener.getNewEntities(session));
299
            } else {
300
                result = new MergeResult(persistentObject, null);
301
            }
302
            return result;
303
        } finally {
304
            PostMergeEntityListener.removeSession(session);
305
        }
306
    }
307

    
308
    @Override
309
    public T merge(T transientObject) throws DataAccessException {
310
        Session session = getSession();
311
        @SuppressWarnings("unchecked")
312
        T persistentObject = (T) session.merge(transientObject);
313
        if (logger.isDebugEnabled()) {
314
            logger.debug("dao merge end");
315
        }
316
        return persistentObject;
317
    }
318

    
319
    @Override
320
    public UUID saveOrUpdate(T transientObject) throws DataAccessException {
321
        if (transientObject == null) {
322
            logger.warn("Object to save should not be null. NOP");
323
            return null;
324
        }
325
        try {
326
            if (logger.isDebugEnabled()) {
327
                logger.debug("dao saveOrUpdate start...");
328
            }
329
            if (logger.isDebugEnabled()) {
330
                logger.debug("transientObject(" + transientObject.getClass().getSimpleName() + ") ID:"
331
                        + transientObject.getId() + ", UUID: " + transientObject.getUuid());
332
            }
333
            Session session = getSession();
334
            if (transientObject.getId() != 0 && VersionableEntity.class.isAssignableFrom(transientObject.getClass())) {
335
                VersionableEntity versionableEntity = (VersionableEntity) transientObject;
336
                versionableEntity.setUpdated(new DateTime());
337
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
338
                if (authentication != null && authentication.getPrincipal() != null
339
                        && authentication.getPrincipal() instanceof User) {
340
                    User user = (User) authentication.getPrincipal();
341
                    versionableEntity.setUpdatedBy(user);
342
                }
343
            }
344
            session.saveOrUpdate(transientObject);
345
            if (logger.isDebugEnabled()) {
346
                logger.debug("dao saveOrUpdate end");
347
            }
348
            return transientObject.getUuid();
349
        } catch (NonUniqueObjectException e) {
350
            logger.error("Error in CdmEntityDaoBase.saveOrUpdate(obj). ID=" + e.getIdentifier() + ". Class="
351
                    + e.getEntityName());
352
            logger.error(e.getMessage());
353

    
354
            e.printStackTrace();
355
            throw e;
356
        } catch (HibernateException e) {
357

    
358
            e.printStackTrace();
359
            throw e;
360
        }
361
    }
362

    
363
    @Override
364
    public <S extends T> S save(S newInstance) throws DataAccessException {
365
        if (newInstance == null) {
366
            logger.warn("Object to save should not be null. NOP");
367
            return null;
368
        }
369
        getSession().save(newInstance);
370
        return newInstance;
371
    }
372

    
373
    @Override
374
    public UUID update(T transientObject) throws DataAccessException {
375
        if (transientObject == null) {
376
            logger.warn("Object to update should not be null. NOP");
377
            return null;
378
        }
379
        getSession().update(transientObject);
380
        return transientObject.getUuid();
381
    }
382

    
383
    @Override
384
    public UUID refresh(T persistentObject) throws DataAccessException {
385
        getSession().refresh(persistentObject);
386
        return persistentObject.getUuid();
387
    }
388

    
389
    @Override
390
    public UUID delete(T persistentObject) throws DataAccessException {
391
        if (persistentObject == null) {
392
            logger.warn(type.getName() + " was 'null'");
393
            return null;
394
        }
395

    
396
        // Merge the object in if it is detached
397
        //
398
        // I think this is preferable to catching lazy initialization errors
399
        // as that solution only swallows and hides the exception, but doesn't
400
        // actually solve it.
401
        persistentObject = (T) getSession().merge(persistentObject);
402
        getSession().delete(persistentObject);
403
        return persistentObject.getUuid();
404
    }
405

    
406
    @Override
407
    public T findById(int id) throws DataAccessException {
408
        return getSession().get(type, id);
409
    }
410

    
411
    @Override
412
    public T findByUuid(UUID uuid) throws DataAccessException {
413
        return this.findByUuid(uuid, INCLUDE_UNPUBLISHED);
414
    }
415

    
416
    protected T findByUuid(UUID uuid, boolean includeUnpublished) throws DataAccessException {
417
        Session session = getSession();
418
        Criteria crit = session.createCriteria(type);
419
        crit.add(Restrictions.eq("uuid", uuid));
420
        crit.addOrder(Order.desc("created"));
421
        if (IPublishable.class.isAssignableFrom(type) && !includeUnpublished) {
422
            crit.add(Restrictions.eq("publish", Boolean.TRUE));
423
        }
424

    
425
        @SuppressWarnings("unchecked")
426
        List<T> results = crit.list();
427
        Set<T> resultSet = new HashSet<>();
428
        resultSet.addAll(results);
429
        if (resultSet.isEmpty()) {
430
            return null;
431
        } else {
432
            if (resultSet.size() > 1) {
433
                logger.error("findByUuid() delivers more than one result for UUID: " + uuid);
434
            }
435
            return results.get(0);
436
        }
437
    }
438

    
439
    @Override
440
    public T findByUuidWithoutFlush(UUID uuid) throws DataAccessException {
441
        Session session = getSession();
442
        FlushMode currentFlushMode = session.getFlushMode();
443
        try {
444
            // set flush mode to manual so that the session does not flush
445
            // when before performing the query
446
            session.setFlushMode(FlushMode.MANUAL);
447
            Criteria crit = session.createCriteria(type);
448
            crit.add(Restrictions.eq("uuid", uuid));
449
            crit.addOrder(Order.desc("created"));
450
            @SuppressWarnings("unchecked")
451
            List<T> results = crit.list();
452
            if (results.isEmpty()) {
453
                return null;
454
            } else {
455
                if (results.size() > 1) {
456
                    logger.error("findByUuid() delivers more than one result for UUID: " + uuid);
457
                }
458
                return results.get(0);
459
            }
460
        } finally {
461
            // set back the session flush mode
462
            if (currentFlushMode != null) {
463
                session.setFlushMode(currentFlushMode);
464
            }
465
        }
466
    }
467

    
468
    @Override
469
    public List<T> loadList(Collection<Integer> ids, List<OrderHint> orderHints, List<String> propertyPaths) throws DataAccessException {
470

    
471
        if (ids.isEmpty()) {
472
            return new ArrayList<>(0);
473
        }
474

    
475
        Criteria criteria = prepareList(null, ids, null, null, orderHints, "id");
476

    
477
        if (logger.isDebugEnabled()) {
478
            logger.debug(criteria.toString());
479
        }
480

    
481
        @SuppressWarnings("unchecked")
482
        List<T> result = criteria.list();
483
        defaultBeanInitializer.initializeAll(result, propertyPaths);
484
        return result;
485
    }
486

    
487
    @Override
488
    public List<T> list(Collection<UUID> uuids, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
489
            List<String> propertyPaths) throws DataAccessException {
490

    
491
        if (uuids == null || uuids.isEmpty()) {
492
            return new ArrayList<>();
493
        }
494

    
495
        Criteria criteria = prepareList(null, uuids, pageSize, pageNumber, orderHints, "uuid");
496
        @SuppressWarnings("unchecked")
497
        List<T> result = criteria.list();
498
        defaultBeanInitializer.initializeAll(result, propertyPaths);
499
        return result;
500
    }
501

    
502
    @Override
503
    public <S extends T> List<S> list(Class<S> clazz, Collection<UUID> uuids, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
504
            List<String> propertyPaths) throws DataAccessException {
505

    
506
        if (uuids == null || uuids.isEmpty()) {
507
            return new ArrayList<>();
508
        }
509

    
510
        Criteria criteria = prepareList(clazz, uuids, pageSize, pageNumber, orderHints, "uuid");
511
        @SuppressWarnings("unchecked")
512
        List<S> result = criteria.list();
513
        defaultBeanInitializer.initializeAll(result, propertyPaths);
514
        return result;
515
    }
516

    
517
    /**
518
     * {@inheritDoc}
519
     */
520
    @Override
521
    public <S extends T> List<S> list(Class<S> type, List<Restriction<?>> restrictions, Integer limit, Integer start,
522
            List<OrderHint> orderHints, List<String> propertyPaths) {
523

    
524
        Criteria criteria = createCriteria(type, restrictions, false);
525

    
526
        addLimitAndStart(criteria, limit, start);
527
        addOrder(criteria, orderHints);
528

    
529
        @SuppressWarnings("unchecked")
530
        List<S> result = criteria.list();
531
        defaultBeanInitializer.initializeAll(result, propertyPaths);
532
        return result;
533
    }
534

    
535
    /**
536
     * @param restrictions
537
     * @param criteria
538
     */
539
    private void addRestrictions(List<Restriction<?>> restrictions, DetachedCriteria criteria) {
540

    
541
        if(restrictions == null || restrictions.isEmpty()){
542
            return ;
543
        }
544

    
545
        List<CriterionWithOperator> perProperty = new ArrayList<>(restrictions.size());
546
        Map<String, String> aliases = new HashMap<>();
547

    
548

    
549

    
550
        for(Restriction<?> restriction : restrictions){
551
            Collection<? extends Object> values = restriction.getValues();
552
            JoinType jointype = LEFTOUTER_OPS.contains(restriction.getOperator()) ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN;
553
            if(values != null && !values.isEmpty()){
554
                // ---
555
                String propertyPath = restriction.getPropertyName();
556
                String[] props =  propertyPath.split("\\.");
557
                String propertyName;
558
                if(props.length == 1){
559
                    // direct property of the base type of the criteria
560
                    propertyName = propertyPath;
561
                } else {
562
                    // create aliases if the propertyName is a dot separated property path
563
                    String aĺiasKey = jointype.name() + "_";
564
                    String aliasedProperty = null;
565
                    String alias = "";
566
                    for(int p = 0; p < props.length -1; p++){
567
                        aĺiasKey = aĺiasKey + (aĺiasKey.isEmpty() ? "" : ".") + props[p];
568
                        aliasedProperty = alias + (alias.isEmpty() ? "" : ".") + props[p];
569
                        if(!aliases.containsKey(aliasedProperty)){
570
                            alias = alias + (alias.isEmpty() ? "" : "_" ) + props[p];
571
                            aliases.put(aĺiasKey, alias);
572
                            criteria.createAlias(aliasedProperty, alias, jointype);
573
                            if(logger.isDebugEnabled()){
574
                                logger.debug("addRestrictions() alias created with aliasKey " + aĺiasKey + " => " + aliasedProperty + " as " + alias);
575
                            }
576
                        }
577
                    }
578
                    propertyName = alias + "." + props[props.length -1];
579
                }
580
                // ---
581
                Criterion[] predicates = new Criterion[values.size()];
582
                int i = 0;
583
                for(Object v : values){
584
                    Criterion criterion = createRestriction(propertyName, v, restriction.getMatchMode());
585
                    if(restriction.isNot()){
586
                        if(props.length > 1){
587
                            criterion = Restrictions.or(Restrictions.not(criterion), Restrictions.isNull(propertyName));
588
                        } else {
589
                            criterion = Restrictions.not(criterion);
590
                        }
591
                    }
592
                    predicates[i++] = criterion;
593
                    if(logger.isDebugEnabled()){
594
                        logger.debug("addRestrictions() predicate with " + propertyName + " " + (restriction.getMatchMode() == null ? "=" : restriction.getMatchMode().name()) + " " + v.toString());
595
                    }
596
                }
597
                if(restriction.getOperator() == Operator.AND_NOT){
598
                    perProperty.add(new CriterionWithOperator(restriction.getOperator(), Restrictions.and(predicates)));
599
                } else {
600
                    perProperty.add(new CriterionWithOperator(restriction.getOperator(), Restrictions.or(predicates)));
601
                }
602
            } // check has values
603
        } // loop over restrictions
604

    
605
        Restriction.Operator firstOperator = null;
606
        if(!perProperty.isEmpty()){
607
            LogicalExpression logicalExpression = null;
608
            for(CriterionWithOperator cwo : perProperty){
609
                if(logicalExpression == null){
610
                    firstOperator = cwo.operator;
611
                    logicalExpression = Restrictions.and(Restrictions.sqlRestriction("1=1"), cwo.criterion);
612
                } else {
613
                    switch(cwo.operator){
614
                        case AND:
615
                        case AND_NOT:
616
                            logicalExpression = Restrictions.and(logicalExpression, cwo.criterion);
617
                            break;
618
                        case OR:
619
                        case OR_NOT:
620
                            logicalExpression = Restrictions.or(logicalExpression, cwo.criterion);
621
                            break;
622
                        default:
623
                            throw new RuntimeException("Unsupported Operator");
624
                    }
625
                }
626

    
627
            }
628

    
629

    
630
            criteria.add(logicalExpression);
631
//            if(firstOperator == Operator.OR){
632
//                // OR
633
//            } else {
634
//                // AND
635
//                criteria.add(Restrictions.and(queryStringCriterion, logicalExpression));
636
//            }
637
        }
638
        if(logger.isDebugEnabled()){
639
            logger.debug("addRestrictions() final criteria: " + criteria.toString());
640
        }
641
    }
642

    
643
    /**
644
     * @param propertyName
645
     * @param value
646
     * @param matchMode
647
     *            is only applied if the <code>value</code> is a
648
     *            <code>String</code> object
649
     * @param criteria
650
     * @return
651
     */
652
    private Criterion createRestriction(String propertyName, Object value, MatchMode matchMode) {
653

    
654
        Criterion restriction;
655
        if (value == null) {
656
            if (logger.isDebugEnabled()) {
657
                logger.debug("createRestriction() " + propertyName + " is null ");
658
            }
659
            restriction = Restrictions.isNull(propertyName);
660
        } else if (matchMode == null || !(value instanceof String)) {
661
            if (logger.isDebugEnabled()) {
662
                logger.debug("createRestriction() " + propertyName + " = " + value.toString());
663
            }
664
            restriction = Restrictions.eq(propertyName, value);
665
        } else {
666
            String queryString = (String) value;
667
            if (logger.isDebugEnabled()) {
668
                logger.debug("createRestriction() " + propertyName + " " + matchMode.getMatchOperator() + " "
669
                        + matchMode.queryStringFrom(queryString));
670
            }
671
            switch(matchMode){
672
            case BEGINNING:
673
                restriction = Restrictions.ilike(propertyName, queryString, org.hibernate.criterion.MatchMode.START);
674
                break;
675
            case END:
676
                restriction = Restrictions.ilike(propertyName, queryString, org.hibernate.criterion.MatchMode.END);
677
                break;
678
            case LIKE:
679
                restriction = Restrictions.ilike(propertyName, matchMode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.ANYWHERE);
680
                break;
681
            case EXACT:
682
                restriction = Restrictions.ilike(propertyName, queryString, org.hibernate.criterion.MatchMode.EXACT);
683
                break;
684
            case ANYWHERE:
685
                restriction = Restrictions.ilike(propertyName, queryString, org.hibernate.criterion.MatchMode.ANYWHERE);
686
                break;
687
            default:
688
                throw new RuntimeException("Unknown MatchMode: " + matchMode.name());
689
            }
690
        }
691
        return restriction;
692
    }
693

    
694
    /**
695
     * {@inheritDoc}
696
     */
697
    @Override
698
    public long count(Class<? extends T> type, List<Restriction<?>> restrictions) {
699

    
700
        Criteria criteria = createCriteria(type, restrictions, false);
701

    
702
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
703

    
704
        return (Long) criteria.uniqueResult();
705

    
706
    }
707

    
708
    /**
709
     * @param uuids
710
     * @param pageSize
711
     * @param pageNumber
712
     * @param orderHints
713
     * @param propertyName
714
     * @return
715
     */
716
    private Criteria prepareList(Class<? extends T> clazz, Collection<?> uuids, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
717
            String propertyName) {
718
        if (clazz == null){
719
            clazz = type;
720
        }
721
        Criteria criteria = getSession().createCriteria(clazz);
722
        criteria.add(Restrictions.in(propertyName, uuids));
723

    
724
        if (pageSize != null) {
725
            criteria.setMaxResults(pageSize);
726
            if (pageNumber != null) {
727
                criteria.setFirstResult(pageNumber * pageSize);
728
            } else {
729
                criteria.setFirstResult(0);
730
            }
731
        }
732

    
733
        if (orderHints == null) {
734
            orderHints = OrderHint.defaultOrderHintsFor(type);
735
        }
736
        addOrder(criteria, orderHints);
737
        return criteria;
738
    }
739

    
740
    /**
741
     * @param clazz
742
     * @return
743
     */
744
    private Criteria criterionForType(Class<? extends T> clazz) {
745
        return  getSession().createCriteria(entityType(clazz));
746
    }
747

    
748
    protected Class<? extends T> entityType(Class<? extends T> clazz){
749
        if (clazz != null) {
750
            return clazz;
751
        } else {
752
            return type;
753
        }
754
    }
755

    
756
    @Override
757
    public T load(UUID uuid) {
758
        T bean = findByUuid(uuid);
759
        if (bean == null) {
760
            return null;
761
        }
762
        defaultBeanInitializer.load(bean);
763

    
764
        return bean;
765
    }
766

    
767
    @Override
768
    public T load(int id, List<String> propertyPaths) {
769
        T bean = findById(id);
770
        if (bean == null) {
771
            return bean;
772
        }
773
        defaultBeanInitializer.initialize(bean, propertyPaths);
774

    
775
        return bean;
776
    }
777

    
778
    @Override
779
    public T loadProxy(int id){
780
        return this.getSession().load(type, id);
781
    }
782

    
783
    @Override
784
    public T load(UUID uuid, List<String> propertyPaths) {
785
        return this.load(uuid, INCLUDE_UNPUBLISHED, propertyPaths);
786
    }
787

    
788
    protected T load(UUID uuid, boolean includeUnpublished, List<String> propertyPaths) {
789
        T bean = findByUuid(uuid, includeUnpublished);
790
        if (bean == null) {
791
            return bean;
792
        }
793
        defaultBeanInitializer.initialize(bean, propertyPaths);
794

    
795
        return bean;
796
    }
797

    
798
    @Override
799
    public Boolean exists(UUID uuid) {
800
        if (findByUuid(uuid) == null) {
801
            return false;
802
        }
803
        return true;
804
    }
805

    
806
    @Override
807
    public long count() {
808
        return count(type);
809
    }
810

    
811
    @Override
812
    public long count(Class<? extends T> clazz) {
813
        Session session = getSession();
814
        Criteria criteria = null;
815
        if (clazz == null) {
816
            criteria = session.createCriteria(type);
817
        } else {
818
            criteria = session.createCriteria(clazz);
819
        }
820
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
821

    
822
        // since hibernate 4 (or so) uniqueResult returns Long, not Integer,
823
        // therefore needs
824
        // to be casted. Think about returning long rather then int!
825
        return (long) criteria.uniqueResult();
826
    }
827

    
828
    @Override
829
    public List<T> list(Integer limit, Integer start) {
830
        return list(limit, start, null);
831
    }
832

    
833
    @Override
834
    public List<Object[]> group(Class<? extends T> clazz, Integer limit, Integer start, List<Grouping> groups,
835
            List<String> propertyPaths) {
836

    
837
        Criteria criteria = null;
838
        criteria = criterionForType(clazz);
839

    
840
        addGroups(criteria, groups);
841

    
842
        if (limit != null) {
843
            criteria.setFirstResult(start);
844
            criteria.setMaxResults(limit);
845
        }
846

    
847
        @SuppressWarnings("unchecked")
848
        List<Object[]> result = criteria.list();
849

    
850
        if (propertyPaths != null && !propertyPaths.isEmpty()) {
851
            for (Object[] objects : result) {
852
                defaultBeanInitializer.initialize(objects[0], propertyPaths);
853
            }
854
        }
855

    
856
        return result;
857
    }
858

    
859
    protected void countGroups(DetachedCriteria criteria, List<Grouping> groups) {
860
        if (groups != null) {
861

    
862
            Map<String, String> aliases = new HashMap<String, String>();
863

    
864
            for (Grouping grouping : groups) {
865
                if (grouping.getAssociatedObj() != null) {
866
                    String alias = null;
867
                    if ((alias = aliases.get(grouping.getAssociatedObj())) == null) {
868
                        alias = grouping.getAssociatedObjectAlias();
869
                        aliases.put(grouping.getAssociatedObj(), alias);
870
                        criteria.createAlias(grouping.getAssociatedObj(), alias);
871
                    }
872
                }
873
            }
874

    
875
            ProjectionList projectionList = Projections.projectionList();
876

    
877
            for (Grouping grouping : groups) {
878
                grouping.addProjection(projectionList);
879
            }
880
            criteria.setProjection(projectionList);
881
        }
882
    }
883

    
884
    protected void addGroups(Criteria criteria, List<Grouping> groups) {
885
        if (groups != null) {
886

    
887
            Map<String, String> aliases = new HashMap<String, String>();
888

    
889
            for (Grouping grouping : groups) {
890
                if (grouping.getAssociatedObj() != null) {
891
                    String alias = null;
892
                    if ((alias = aliases.get(grouping.getAssociatedObj())) == null) {
893
                        alias = grouping.getAssociatedObjectAlias();
894
                        aliases.put(grouping.getAssociatedObj(), alias);
895
                        criteria.createAlias(grouping.getAssociatedObj(), alias);
896
                    }
897
                }
898
            }
899

    
900
            ProjectionList projectionList = Projections.projectionList();
901

    
902
            for (Grouping grouping : groups) {
903
                grouping.addProjection(projectionList);
904
            }
905
            criteria.setProjection(projectionList);
906

    
907
            for (Grouping grouping : groups) {
908
                grouping.addOrder(criteria);
909

    
910
            }
911
        }
912
    }
913

    
914
    @Override
915
    public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints) {
916
        return list(limit, start, orderHints, null);
917
    }
918

    
919
    @Override
920
    public List<T> list(Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
921
        Criteria criteria = getSession().createCriteria(type);
922
        if (limit != null) {
923
            criteria.setFirstResult(start);
924
            criteria.setMaxResults(limit);
925
        }
926

    
927
        addOrder(criteria, orderHints);
928
        @SuppressWarnings("unchecked")
929
        List<T> results = criteria.list();
930

    
931
        defaultBeanInitializer.initializeAll(results, propertyPaths);
932
        return results;
933
    }
934

    
935
    @Override
936
    public <S extends T> List<S> list(Class<S> clazz, Integer limit, Integer start, List<OrderHint> orderHints,
937
            List<String> propertyPaths) {
938
        Criteria criteria = null;
939
        if (clazz == null) {
940
            criteria = getSession().createCriteria(type);
941
        } else {
942
            criteria = getSession().createCriteria(clazz);
943
        }
944

    
945
        addLimitAndStart(criteria, limit, start);
946

    
947
        addOrder(criteria, orderHints);
948

    
949
        @SuppressWarnings("unchecked")
950
        List<S> results = criteria.list();
951

    
952
        defaultBeanInitializer.initializeAll(results, propertyPaths);
953
        return results;
954
    }
955

    
956
    public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start, List<OrderHint> orderHints) {
957
        return list(type, limit, start, orderHints, null);
958
    }
959

    
960
    @Override
961
    public <S extends T> List<S> list(Class<S> type, Integer limit, Integer start) {
962
        return list(type, limit, start, null, null);
963
    }
964

    
965
    @Override
966
    public Class<T> getType() {
967
        return type;
968
    }
969

    
970
    protected void setPagingParameter(Query query, Integer pageSize, Integer pageIndex) {
971
        if (pageSize != null) {
972
            query.setMaxResults(pageSize);
973
            if (pageIndex != null) {
974
                query.setFirstResult(pageIndex * pageSize);
975
            } else {
976
                query.setFirstResult(0);
977
            }
978
        }
979
    }
980

    
981
    protected void setPagingParameter(AuditQuery query, Integer pageSize, Integer pageIndex) {
982
        if (pageSize != null) {
983
            query.setMaxResults(pageSize);
984
            if (pageIndex != null) {
985
                query.setFirstResult(pageIndex * pageSize);
986
            } else {
987
                query.setFirstResult(0);
988
            }
989
        }
990
    }
991

    
992
    @Override
993
    public long count(T example, Set<String> includeProperties) {
994
        Criteria criteria = getSession().createCriteria(example.getClass());
995
        addExample(criteria, example, includeProperties);
996

    
997
        criteria.setProjection(Projections.rowCount());
998
        return (Long) criteria.uniqueResult();
999
    }
1000

    
1001
    protected void addExample(Criteria criteria, T example, Set<String> includeProperties) {
1002
        if (includeProperties != null && !includeProperties.isEmpty()) {
1003
            criteria.add(Example.create(example).setPropertySelector(new PropertySelectorImpl(includeProperties)));
1004
            ClassMetadata classMetadata = getSession().getSessionFactory().getClassMetadata(example.getClass());
1005
            for (String property : includeProperties) {
1006
                Type type = classMetadata.getPropertyType(property);
1007
                if (type.isEntityType()) {
1008
                    try {
1009
                        Field field = ReflectionUtils.findField(example.getClass(), property);
1010
                        field.setAccessible(true);
1011
                        Object value = field.get(example);
1012
                        if (value != null) {
1013
                            criteria.add(Restrictions.eq(property, value));
1014
                        } else {
1015
                            criteria.add(Restrictions.isNull(property));
1016
                        }
1017
                    } catch (SecurityException se) {
1018
                        throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property,
1019
                                se);
1020
                    } catch (HibernateException he) {
1021
                        throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property,
1022
                                he);
1023
                    } catch (IllegalArgumentException iae) {
1024
                        throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property,
1025
                                iae);
1026
                    } catch (IllegalAccessException ie) {
1027
                        throw new InvalidDataAccessApiUsageException("Tried to add criteria for property " + property,
1028
                                ie);
1029
                    }
1030
                }
1031
            }
1032
        } else {
1033
            criteria.add(Example.create(example));
1034
        }
1035
    }
1036

    
1037
    /**
1038
     *
1039
     * NOTE: We can't reuse
1040
     * {@link #list(Class, String, Object, MatchMode, Integer, Integer, List, List)
1041
     * here due to different default behavior of the <code>matchmode</code>
1042
     * parameter.
1043
     *
1044
     * @param clazz
1045
     * @param param
1046
     * @param queryString
1047
     * @param matchmode
1048
     * @param criterion
1049
     * @param pageSize
1050
     * @param pageNumber
1051
     * @param orderHints
1052
     * @param propertyPaths
1053
     * @return
1054
     */
1055
    @Override
1056
    public <S extends T> List<S> findByParam(Class<S> clazz, String param, String queryString, MatchMode matchmode,
1057
            List<Criterion> criterion, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
1058
            List<String> propertyPaths) {
1059
        Set<String> stringSet = new HashSet<>();
1060
        stringSet.add(param);
1061
        return this.findByParam(clazz, stringSet, queryString, matchmode,
1062
                criterion, pageSize, pageNumber, orderHints,
1063
                propertyPaths);
1064
    }
1065

    
1066
    @Override
1067
    public <S extends T> List<S> findByParam(Class<S> clazz, Set<String> params, String queryString, MatchMode matchmode,
1068
            List<Criterion> criterion, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
1069
            List<String> propertyPaths) {
1070

    
1071
        Criteria criteria = criterionForType(clazz);
1072

    
1073
        if (queryString != null) {
1074
            Set<Criterion> criterions = new HashSet<>();
1075
            for (String param: params){
1076
                Criterion crit;
1077
                if (matchmode == null) {
1078
                     crit = Restrictions.ilike(param, queryString);
1079
                } else if (matchmode == MatchMode.BEGINNING) {
1080
                     crit = Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.START);
1081
                } else if (matchmode == MatchMode.END) {
1082
                    crit = Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.END);
1083
                } else if (matchmode == MatchMode.EXACT) {
1084
                    crit = Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.EXACT);
1085
                } else {
1086
                    crit = Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.ANYWHERE);
1087
                }
1088
                criterions.add(crit);
1089
            }
1090
            if (criterions.size()>1){
1091
                Iterator<Criterion> critIterator = criterions.iterator();
1092
                Disjunction disjunction = Restrictions.disjunction();
1093
                while (critIterator.hasNext()){
1094
                    disjunction.add(critIterator.next());
1095
                }
1096

    
1097
                criteria.add(disjunction);
1098

    
1099
            }else{
1100
                if (!criterions.isEmpty()){
1101
                    criteria.add(criterions.iterator().next());
1102
                }
1103
            }
1104

    
1105
        }
1106

    
1107
        addCriteria(criteria, criterion);
1108

    
1109
        if (pageSize != null) {
1110
            criteria.setMaxResults(pageSize);
1111
            if (pageNumber != null) {
1112
                criteria.setFirstResult(pageNumber * pageSize);
1113
            } else {
1114
                criteria.setFirstResult(0);
1115
            }
1116
        }
1117

    
1118
        addOrder(criteria, orderHints);
1119

    
1120
        @SuppressWarnings("unchecked")
1121
        List<S> result = criteria.list();
1122
        defaultBeanInitializer.initializeAll(result, propertyPaths);
1123
        return result;
1124
    }
1125

    
1126
    /**
1127
     *
1128
     * @param clazz
1129
     * @param param
1130
     * @param queryString
1131
     * @param matchmode
1132
     * @param criterion
1133
     * @return
1134
     */
1135
    @Override
1136
    public long countByParam(Class<? extends T> clazz, String param, String queryString, MatchMode matchmode,
1137
            List<Criterion> criterion) {
1138

    
1139
        Criteria criteria = null;
1140

    
1141
        criteria = criterionForType(clazz);
1142

    
1143
        if (queryString != null) {
1144
            if (matchmode == null) {
1145
                criteria.add(Restrictions.ilike(param, queryString));
1146
            } else if (matchmode == MatchMode.BEGINNING) {
1147
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.START));
1148
            } else if (matchmode == MatchMode.END) {
1149
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.END));
1150
            } else if (matchmode == MatchMode.EXACT) {
1151
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.EXACT));
1152
            } else {
1153
                criteria.add(Restrictions.ilike(param, queryString, org.hibernate.criterion.MatchMode.ANYWHERE));
1154
            }
1155
        }
1156

    
1157
        addCriteria(criteria, criterion);
1158

    
1159
        criteria.setProjection(Projections.rowCount());
1160

    
1161
        return (Long) criteria.uniqueResult();
1162
    }
1163

    
1164
    /**
1165
     * Creates a criteria query for the CDM <code>type</code> either for counting or listing matching entities.
1166
     * <p>
1167
     * The set of matching entities can be restricted by passing a list  of {@link Restriction} objects.
1168
     * Restrictions can logically combined:
1169
     <pre>
1170
       Arrays.asList(
1171
           new Restriction<String>("titleCache", MatchMode.ANYWHERE, "foo"),
1172
           new Restriction<String>("institute.name", Operator.OR, MatchMode.BEGINNING, "Bar")
1173
       );
1174
     </pre>
1175
     * The first Restriction in the example above by default has the <code>Operator.AND</code> which will be
1176
     * ignored since this is the first restriction. The <code>Operator</code> of further restrictions in the
1177
     * list are used to combine with the previous restriction.
1178
     *
1179
     * @param type
1180
     * @param restrictions
1181
     * @param doCount
1182
     * @return
1183
     */
1184
    protected Criteria createCriteria(Class<? extends T> type, List<Restriction<?>> restrictions, boolean doCount) {
1185

    
1186
        DetachedCriteria idsOnlyCriteria = DetachedCriteria.forClass(entityType(type));
1187
        idsOnlyCriteria.setProjection(Projections.distinct(Projections.id()));
1188

    
1189
        addRestrictions(restrictions, idsOnlyCriteria);
1190

    
1191
        Criteria criteria = criterionForType(type);
1192
        criteria.add(Subqueries.propertyIn("id", idsOnlyCriteria));
1193

    
1194
        if(doCount){
1195
            criteria.setProjection(Projections.rowCount());
1196
        } else {
1197
            idsOnlyCriteria.setProjection(Projections.distinct(Projections.property("id")));
1198
        }
1199

    
1200
        return criteria;
1201
    }
1202

    
1203

    
1204
    @Override
1205
    public <S extends T> List<S> findByParamWithRestrictions(Class<S> clazz, String param, String queryString,
1206
            MatchMode matchmode, List<Restriction<?>> restrictions, Integer pageSize, Integer pageNumber,
1207
            List<OrderHint> orderHints, List<String> propertyPaths) {
1208

    
1209
        List<Restriction<?>> allRestrictions = new ArrayList<>();
1210
        allRestrictions.add(new Restriction<String>(param, matchmode, queryString));
1211
        if(restrictions != null){
1212
            allRestrictions.addAll(restrictions);
1213
        }
1214
        Criteria criteria = createCriteria(clazz, allRestrictions, false);
1215

    
1216
        if (pageSize != null) {
1217
            criteria.setMaxResults(pageSize);
1218
            if (pageNumber != null) {
1219
                criteria.setFirstResult(pageNumber * pageSize);
1220
            } else {
1221
                criteria.setFirstResult(0);
1222
            }
1223
        }
1224

    
1225
        addOrder(criteria, orderHints);
1226

    
1227
        @SuppressWarnings("unchecked")
1228
        List<S> result = criteria.list();
1229
        defaultBeanInitializer.initializeAll(result, propertyPaths);
1230
        return result;
1231

    
1232
    }
1233

    
1234
    @Override
1235
    public long countByParamWithRestrictions(Class<? extends T> clazz, String param, String queryString,
1236
            MatchMode matchmode, List<Restriction<?>> restrictions) {
1237

    
1238
        List<Restriction<?>> allRestrictions = new ArrayList<>();
1239
        allRestrictions.add(new Restriction<String>(param, matchmode, queryString));
1240
        if(restrictions != null){
1241
            allRestrictions.addAll(restrictions);
1242
        }
1243
        Criteria criteria = createCriteria(clazz, allRestrictions, true);
1244

    
1245
        return (Long) criteria.uniqueResult();
1246
    }
1247

    
1248
    @Override
1249
    public <S extends T> List<S> list(S example, Set<String> includeProperties, Integer limit, Integer start,
1250
            List<OrderHint> orderHints, List<String> propertyPaths) {
1251
        Criteria criteria = getSession().createCriteria(example.getClass());
1252
        addExample(criteria, example, includeProperties);
1253

    
1254
        addLimitAndStart(criteria, limit, start);
1255

    
1256
        addOrder(criteria, orderHints);
1257

    
1258
        @SuppressWarnings("unchecked")
1259
        List<S> results = criteria.list();
1260
        defaultBeanInitializer.initializeAll(results, propertyPaths);
1261
        return results;
1262
    }
1263

    
1264
    private class PropertySelectorImpl implements PropertySelector {
1265

    
1266
        private final Set<String> includeProperties;
1267
        /**
1268
         *
1269
         */
1270
        private static final long serialVersionUID = -3175311800911570546L;
1271

    
1272
        public PropertySelectorImpl(Set<String> includeProperties) {
1273
            this.includeProperties = includeProperties;
1274
        }
1275

    
1276
        @Override
1277
        public boolean include(Object propertyValue, String propertyName, Type type) {
1278
            if (includeProperties.contains(propertyName)) {
1279
                return true;
1280
            } else {
1281
                return false;
1282
            }
1283
        }
1284

    
1285
    }
1286

    
1287
    private class CriterionWithOperator {
1288

    
1289
        Restriction.Operator operator;
1290
        Criterion criterion;
1291

    
1292

    
1293
        public CriterionWithOperator(Operator operator, Criterion criterion) {
1294
            super();
1295
            this.operator = operator;
1296
            this.criterion = criterion;
1297
        }
1298

    
1299

    
1300
    }
1301

    
1302
    /**
1303
     * Returns a Criteria for the given {@link Class class} or, if
1304
     * <code>null</code>, for the base {@link Class class} of this DAO.
1305
     *
1306
     * @param clazz
1307
     * @return the Criteria
1308
     */
1309
    protected Criteria getCriteria(Class<? extends CdmBase> clazz) {
1310
        Criteria criteria = null;
1311
        if (clazz == null) {
1312
            criteria = getSession().createCriteria(type);
1313
        } else {
1314
            criteria = getSession().createCriteria(clazz);
1315
        }
1316
        return criteria;
1317
    }
1318

    
1319
    /**
1320
     * @param clazz
1321
     * @param auditEvent
1322
     * @return
1323
     */
1324
    protected AuditQuery makeAuditQuery(Class<? extends CdmBase> clazz, AuditEvent auditEvent) {
1325
        AuditQuery query = null;
1326

    
1327
        if (clazz == null) {
1328
            query = getAuditReader().createQuery().forEntitiesAtRevision(type, auditEvent.getRevisionNumber());
1329
        } else {
1330
            query = getAuditReader().createQuery().forEntitiesAtRevision(clazz, auditEvent.getRevisionNumber());
1331
        }
1332
        return query;
1333
    }
1334

    
1335
    protected AuditReader getAuditReader() {
1336
        return AuditReaderFactory.get(getSession());
1337
    }
1338
}
(3-3/18)