Project

General

Profile

Download (38.2 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.description;
11

    
12
import java.util.ArrayList;
13
import java.util.HashSet;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.Set;
17
import java.util.UUID;
18

    
19
import org.apache.commons.lang.ArrayUtils;
20
import org.apache.logging.log4j.LogManager;
21
import org.apache.logging.log4j.Logger;
22
import org.hibernate.Criteria;
23
import org.hibernate.criterion.Criterion;
24
import org.hibernate.criterion.ProjectionList;
25
import org.hibernate.criterion.Projections;
26
import org.hibernate.criterion.Restrictions;
27
import org.hibernate.envers.query.AuditEntity;
28
import org.hibernate.envers.query.AuditQuery;
29
import org.hibernate.query.Query;
30
import org.springframework.beans.factory.annotation.Qualifier;
31
import org.springframework.stereotype.Repository;
32

    
33
import eu.etaxonomy.cdm.model.common.LSID;
34
import eu.etaxonomy.cdm.model.common.MarkerType;
35
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
36
import eu.etaxonomy.cdm.model.description.DescriptionBase;
37
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
38
import eu.etaxonomy.cdm.model.description.DescriptionType;
39
import eu.etaxonomy.cdm.model.description.Feature;
40
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
41
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
42
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
43
import eu.etaxonomy.cdm.model.description.TaxonDescription;
44
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
45
import eu.etaxonomy.cdm.model.location.NamedArea;
46
import eu.etaxonomy.cdm.model.media.Media;
47
import eu.etaxonomy.cdm.model.name.TaxonName;
48
import eu.etaxonomy.cdm.model.taxon.Taxon;
49
import eu.etaxonomy.cdm.model.term.DefinedTerm;
50
import eu.etaxonomy.cdm.model.view.AuditEvent;
51
import eu.etaxonomy.cdm.persistence.dao.common.OperationNotSupportedInPriorViewException;
52
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
53
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;
54
import eu.etaxonomy.cdm.persistence.dto.SortableTaxonNodeQueryResult;
55
import eu.etaxonomy.cdm.persistence.dto.TermDto;
56
import eu.etaxonomy.cdm.persistence.query.MatchMode;
57
import eu.etaxonomy.cdm.persistence.query.OrderHint;
58

    
59
@Repository
60
@Qualifier("descriptionDaoImpl")
61
public class DescriptionDaoImpl
62
            extends IdentifiableDaoBase<DescriptionBase>
63
            implements IDescriptionDao{
64

    
65
    private static final Logger logger = LogManager.getLogger(DescriptionDaoImpl.class);
66

    
67
    public DescriptionDaoImpl() {
68
        super(DescriptionBase.class);
69
        indexedClasses = new Class[3];
70
        indexedClasses[0] = TaxonDescription.class;
71
        indexedClasses[1] = TaxonNameDescription.class;
72
        indexedClasses[2] = SpecimenDescription.class;
73
    }
74

    
75
//    @Override  //Override for testing
76
//    public DescriptionBase load(UUID uuid, List<String> propertyPaths){
77
//    	DescriptionBase bean = findByUuid(uuid);
78
//        if(bean == null){
79
//            return bean;
80
//        }
81
//        defaultBeanInitializer.initialize(bean, propertyPaths);
82
//
83
//        return bean;
84
//    }
85

    
86
    @Override
87
    public long countDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm status) {
88
        checkNotInPriorView("DescriptionDaoImpl.countDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTermBase status)");
89
        Query<Long> query = null;
90

    
91
        if(status == null) {
92
            query = getSession().createQuery("select count(distinct description) from TaxonDescription description left join description.descriptionElements element join element.area area where area in (:namedAreas)", Long.class);
93
        } else {
94
            query = getSession().createQuery("select count(distinct description) from TaxonDescription description left join description.descriptionElements element join element.area area  join element.status status where area in (:namedAreas) and status = :status", Long.class);
95
            query.setParameter("status", status);
96
        }
97
        query.setParameterList("namedAreas", namedAreas);
98

    
99
        return query.uniqueResult();
100
    }
101

    
102
    @Override
103
    public <T extends DescriptionElementBase> long countDescriptionElements(DescriptionBase description, Set<Feature> features, Class<T> clazz) {
104
        return countDescriptionElements(description, null, features, clazz);
105
    }
106

    
107
    @Override
108
    public <T extends DescriptionElementBase> long countDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
109
            Set<Feature> features, Class<T> clazz) {
110
        AuditEvent auditEvent = getAuditEventFromContext();
111
        if (clazz == null){
112
            clazz = (Class<T>)DescriptionElementBase.class;
113
        }
114
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
115
            Criteria criteria = getCriteria(clazz);
116

    
117
            if(description != null) {
118
                criteria.add(Restrictions.eq("inDescription", description));
119
            }
120

    
121
            if(descriptionType != null) {
122
                criteria.createAlias("inDescription", "d").add(Restrictions.eq("d.class", descriptionType));
123
            }
124

    
125
            if(features != null && !features.isEmpty()) {
126
                criteria.add(Restrictions.in("feature", features));
127
            }
128

    
129
            criteria.setProjection(Projections.rowCount());
130

    
131
            return (Long)criteria.uniqueResult();
132
        } else {
133
            if(features != null && !features.isEmpty()) {
134
                long count = 0;
135
                for(Feature f : features) {
136
                    AuditQuery query = null;
137
                    query = makeAuditQuery(clazz, auditEvent);
138

    
139
                    if(description != null) {
140
                        query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
141
                    }
142

    
143
                    if(descriptionType != null) {
144
                        query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
145
                    }
146

    
147
                    query.add(AuditEntity.relatedId("feature").eq(f.getId()));
148
                    query.addProjection(AuditEntity.id().count());
149
                    count += (Long)query.getSingleResult();
150
                }
151

    
152
                return count;
153
            } else {
154
                AuditQuery query = makeAuditQuery(clazz, auditEvent);
155

    
156
                if(description != null) {
157
                    query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
158
                }
159
                if(descriptionType != null) {
160
                    query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
161
                }
162

    
163
                query.addProjection(AuditEntity.id().count());
164
                return (Long)query.getSingleResult();
165
            }
166
        }
167
    }
168

    
169
    @Override
170
    public long countDescriptions(Class<? extends DescriptionBase> clazz, Boolean hasImages, Boolean hasText, Set<Feature> features) {
171
        checkNotInPriorView("DescriptionDaoImpl.countDescriptions(Class<TYPE> type, Boolean hasImages, Boolean hasText, Set<Feature> features)");
172

    
173
        Criteria inner = getCriteria(clazz);
174

    
175
        Criteria elementsCriteria = inner.createCriteria("descriptionElements");
176
        if(hasText != null) {
177
            if(hasText) {
178
                elementsCriteria.add(Restrictions.isNotEmpty("multilanguageText"));
179
            } else {
180
                elementsCriteria.add(Restrictions.isEmpty("multilanguageText"));
181
            }
182
        }
183

    
184
        if(hasImages != null) {
185
            if(hasImages) {
186
                elementsCriteria.add(Restrictions.isNotEmpty("media"));
187
            } else {
188
                elementsCriteria.add(Restrictions.isEmpty("media"));
189
            }
190
        }
191

    
192
        if(features != null && !features.isEmpty()) {
193
            elementsCriteria.add(Restrictions.in("feature", features));
194
        }
195

    
196
        inner.setProjection(Projections.countDistinct("id"));
197

    
198
        return (Long)inner.uniqueResult();
199
    }
200

    
201
    @Override
202
    public long countTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes,
203
            Set<NamedArea> geographicalScopes, Set<MarkerType> markerTypes, Set<DescriptionType> descriptionTypes) {
204
        AuditEvent auditEvent = getAuditEventFromContext();
205
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
206
            Criteria criteria = getCriteria(TaxonDescription.class);
207

    
208
            if(taxon != null) {
209
                criteria.add(Restrictions.eq("taxon", taxon));
210
            }
211

    
212
            if(scopes != null && !scopes.isEmpty()) {
213
                Set<Integer> scopeIds = new HashSet<>();
214
                for(DefinedTerm s : scopes) {
215
                    scopeIds.add(s.getId());
216
                }
217
                criteria.createCriteria("scopes").add(Restrictions.in("id", scopeIds));
218
            }
219

    
220
            if(geographicalScopes != null && !geographicalScopes.isEmpty()) {
221
                Set<Integer> geoScopeIds = new HashSet<>();
222
                for(NamedArea n : geographicalScopes) {
223
                    geoScopeIds.add(n.getId());
224
                }
225
                criteria.createCriteria("geoScopes").add(Restrictions.in("id", geoScopeIds));
226
            }
227

    
228
            addMarkerTypesCriterion(markerTypes, criteria);
229
            addDescriptionTypesCriterion(descriptionTypes, criteria);
230

    
231
            criteria.setProjection(Projections.rowCount());
232

    
233
            return (Long)criteria.uniqueResult();
234
        } else {
235
            if((scopes == null || scopes.isEmpty())&& (geographicalScopes == null || geographicalScopes.isEmpty()) && (markerTypes == null || markerTypes.isEmpty())) {
236
                AuditQuery query = makeAuditQuery(TaxonDescription.class,auditEvent);
237
                if(taxon != null) {
238
                    query.add(AuditEntity.relatedId("taxon").eq(taxon.getId()));
239
                }
240

    
241
                query.addProjection(AuditEntity.id().count());
242

    
243
                return (Long)query.getSingleResult();
244
            } else {
245
                throw new OperationNotSupportedInPriorViewException("countTaxonDescriptions(Taxon taxon, Set<Scope> scopes,Set<NamedArea> geographicalScopes)");
246
            }
247
        }
248
    }
249

    
250
    private void addDescriptionTypesCriterion(Set<DescriptionType> descriptionTypes, Criteria criteria) {
251
        if(descriptionTypes != null && !descriptionTypes.isEmpty()) {
252
            Set<Criterion> typeCriteria = new HashSet<>();
253
            for (DescriptionType descriptionType : descriptionTypes) {
254
                typeCriteria.add(Restrictions.sqlRestriction("{alias}.types like '%"+descriptionType.getKey()+"%'"));
255
            }
256
            criteria.add(Restrictions.and(typeCriteria.toArray(new Criterion[]{})));
257
        }
258
    }
259

    
260
    /**
261
     * @param markerTypes
262
     * @param criteria
263
     *
264
     */
265
    //TODO move to AnnotatableEntityDao(?)
266
    private void addMarkerTypesCriterion(Set<MarkerType> markerTypes, Criteria criteria) {
267

    
268
        if(markerTypes != null && !markerTypes.isEmpty()) {
269
            Set<Integer> markerTypeIds = new HashSet<Integer>();
270
            for(MarkerType markerType : markerTypes) {
271
                markerTypeIds.add(markerType.getId());
272
            }
273
            criteria.createCriteria("markers").add(Restrictions.eq("flag", true))
274
                    .createAlias("markerType", "mt")
275
                     .add(Restrictions.in("mt.id", markerTypeIds));
276
        } else if (markerTypes != null && markerTypes.isEmpty()){
277
            //AT: added in case the projects requires an third state description, An empty Marker type set
278
        }
279
    }
280
    @Override
281
    public <T extends DescriptionElementBase> List<T> getDescriptionElements(
282
            DescriptionBase description, Set<Feature> features,
283
            Class<T> clazz, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
284
        return getDescriptionElements(description, null, features, clazz, pageSize, pageNumber, propertyPaths);
285
    }
286

    
287
    @Override
288
    public <T extends DescriptionElementBase> List<T> getDescriptionElements(
289
            DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
290
            Set<Feature> features,
291
            Class<T> clazz,
292
            Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
293

    
294
        AuditEvent auditEvent = getAuditEventFromContext();
295
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
296
            Criteria criteria = null;
297
            if(clazz == null) {
298
                criteria = getSession().createCriteria(DescriptionElementBase.class);
299
            } else {
300
                criteria = getSession().createCriteria(clazz);
301
            }
302

    
303
            if(description != null) {
304
                criteria.add(Restrictions.eq("inDescription", description));
305
            }
306
            if(descriptionType != null) {
307
                criteria.createAlias("inDescription", "d").add(Restrictions.eq("d.class", descriptionType));
308
            }
309

    
310
            if(features != null && !features.isEmpty()) {
311
                criteria.add(Restrictions.in("feature", features));
312
            }
313

    
314
            if(pageSize != null) {
315
                criteria.setMaxResults(pageSize);
316
                if(pageNumber != null) {
317
                    criteria.setFirstResult(pageNumber * pageSize);
318
                }
319
            }
320

    
321
            List<T> results = criteria.list();
322
            defaultBeanInitializer.initializeAll(results, propertyPaths);
323
            return results;
324
        } else {
325
            List<T> result = new ArrayList<T>();
326
            if(features != null && !features.isEmpty()) {
327

    
328
                for(Feature f : features) {
329
                    AuditQuery query = null;
330
                    if(clazz == null) {
331
                        query = getAuditReader().createQuery().forEntitiesAtRevision(DescriptionElementBase.class,auditEvent.getRevisionNumber());
332
                    } else {
333
                        query = getAuditReader().createQuery().forEntitiesAtRevision(clazz,auditEvent.getRevisionNumber());
334
                    }
335

    
336
                    if(description != null) {
337
                        query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
338
                    }
339

    
340
                    if(descriptionType != null) {
341
                        query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
342
                    }
343

    
344
                    query.add(AuditEntity.relatedId("feature").eq(f.getId()));
345
                    result.addAll(query.getResultList());
346
                }
347
            } else {
348
                AuditQuery query = null;
349
                if(clazz == null) {
350
                    query = getAuditReader().createQuery().forEntitiesAtRevision(DescriptionElementBase.class,auditEvent.getRevisionNumber());
351
                } else {
352
                    query = getAuditReader().createQuery().forEntitiesAtRevision(clazz,auditEvent.getRevisionNumber());
353
                }
354

    
355
                if(description != null) {
356
                    query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
357
                }
358

    
359
                if(descriptionType != null) {
360
                    query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
361
                }
362

    
363
                result = query.getResultList();
364
            }
365

    
366
            defaultBeanInitializer.initializeAll(result, propertyPaths);
367
            return result;
368
        }
369
    }
370

    
371
    @Override
372
    public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScopes, Set<MarkerType> markerTypes, Set<DescriptionType> descriptionTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
373
        AuditEvent auditEvent = getAuditEventFromContext();
374
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
375
            Criteria criteria = getSession().createCriteria(TaxonDescription.class);
376

    
377
            if(taxon != null) {
378
                criteria.add(Restrictions.eq("taxon", taxon));
379
            }
380

    
381
            if(scopes != null && !scopes.isEmpty()) {
382
                Set<Integer> scopeIds = new HashSet<Integer>();
383
                for(DefinedTerm s : scopes) {
384
                    scopeIds.add(s.getId());
385
                }
386
                criteria.createCriteria("scopes").add(Restrictions.in("id", scopeIds));
387
            }
388

    
389
            if(geographicalScopes != null && !geographicalScopes.isEmpty()) {
390
                Set<Integer> geoScopeIds = new HashSet<Integer>();
391
                for(NamedArea n : geographicalScopes) {
392
                    geoScopeIds.add(n.getId());
393
                }
394
                criteria.createCriteria("geoScopes").add(Restrictions.in("id", geoScopeIds));
395
            }
396

    
397
            addMarkerTypesCriterion(markerTypes, criteria);
398
            addDescriptionTypesCriterion(descriptionTypes, criteria);
399

    
400
            if(pageSize != null) {
401
                criteria.setMaxResults(pageSize);
402
                if(pageNumber != null) {
403
                    criteria.setFirstResult(pageNumber * pageSize);
404
                }
405
            }
406

    
407
            List<TaxonDescription> results = criteria.list();
408

    
409
            defaultBeanInitializer.initializeAll(results, propertyPaths);
410

    
411
            return results;
412
        } else {
413
            if((scopes == null || scopes.isEmpty())&& (geographicalScopes == null || geographicalScopes.isEmpty())&& (markerTypes == null || markerTypes.isEmpty())) {
414
                AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonDescription.class,auditEvent.getRevisionNumber());
415
                if(taxon != null) {
416
                    query.add(AuditEntity.relatedId("taxon").eq(taxon.getId()));
417
                }
418

    
419
                if(pageSize != null) {
420
                    query.setMaxResults(pageSize);
421
                    if(pageNumber != null) {
422
                        query.setFirstResult(pageNumber * pageSize);
423
                    } else {
424
                        query.setFirstResult(0);
425
                    }
426
                }
427

    
428
                List<TaxonDescription> results = query.getResultList();
429
                defaultBeanInitializer.initializeAll(results, propertyPaths);
430
                return results;
431
            } else {
432
                throw new OperationNotSupportedInPriorViewException("countTaxonDescriptions(Taxon taxon, Set<Scope> scopes,Set<NamedArea> geographicalScopes)");
433
            }
434
        }
435
    }
436

    
437
    @Override
438
    public List<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
439
        AuditEvent auditEvent = getAuditEventFromContext();
440
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
441
            Criteria criteria = getSession().createCriteria(TaxonNameDescription.class);
442

    
443
          if(name != null) {
444
              criteria.add(Restrictions.eq("taxonName", name));
445
          }
446

    
447
          if(pageSize != null) {
448
              criteria.setMaxResults(pageSize);
449
              if(pageNumber != null) {
450
                  criteria.setFirstResult(pageNumber * pageSize);
451
              }
452
          }
453

    
454
          List<TaxonNameDescription> results = criteria.list();
455

    
456
          defaultBeanInitializer.initializeAll(results, propertyPaths);
457

    
458
          return results;
459
        } else {
460
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonNameDescription.class,auditEvent.getRevisionNumber());
461

    
462
            if(name != null) {
463
                query.add(AuditEntity.relatedId("taxonName").eq(name.getId()));
464
            }
465

    
466
            if(pageSize != null) {
467
                  query.setMaxResults(pageSize);
468
                  if(pageNumber != null) {
469
                      query.setFirstResult(pageNumber * pageSize);
470
                  }
471
            }
472

    
473
            List<TaxonNameDescription> results = query.getResultList();
474
            defaultBeanInitializer.initializeAll(results, propertyPaths);
475
            return results;
476
        }
477
    }
478

    
479
    @Override
480
    public long countTaxonNameDescriptions(TaxonName name) {
481
        AuditEvent auditEvent = getAuditEventFromContext();
482
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
483
            Criteria criteria = getCriteria(TaxonNameDescription.class);
484

    
485
            if(name != null) {
486
                criteria.add(Restrictions.eq("taxonName", name));
487
            }
488

    
489
            criteria.setProjection(Projections.rowCount());
490

    
491
            return (Long)criteria.uniqueResult();
492
        } else {
493
            AuditQuery query = makeAuditQuery(TaxonNameDescription.class,auditEvent);
494

    
495
            if(name != null) {
496
                query.add(AuditEntity.relatedId("taxonName").eq(name.getId()));
497
            }
498

    
499
            query.addProjection(AuditEntity.id().count());
500
            return (Long)query.getSingleResult();
501
        }
502
    }
503

    
504
    /**
505
     * Should use a DetachedCriteria & subquery, but HHH-158 prevents this, for now.
506
     *
507
     * e.g. DetachedCriteria inner = DestachedCriteria.forClass(type);
508
     *
509
     * outer.add(Subqueries.propertyIn("id", inner));
510
     */
511
    @Override
512
    public List<DescriptionBase> listDescriptions(Class<? extends DescriptionBase> clazz, Boolean hasImages, Boolean hasText,	Set<Feature> features, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
513
        checkNotInPriorView("DescriptionDaoImpl.listDescriptions(Class<TYPE> type, Boolean hasImages, Boolean hasText,	Set<Feature> features, Integer pageSize, Integer pageNumber)");
514
        Criteria inner = getCriteria(clazz);
515

    
516
        Criteria elementsCriteria = inner.createCriteria("descriptionElements");
517
        if(hasText != null) {
518
            if(hasText) {
519
                elementsCriteria.add(Restrictions.isNotEmpty("multilanguageText"));
520
            } else {
521
                elementsCriteria.add(Restrictions.isEmpty("multilanguageText"));
522
            }
523
        }
524

    
525
        if(hasImages != null) {
526
            if(hasImages) {
527
                elementsCriteria.add(Restrictions.isNotEmpty("media"));
528
            } else {
529
                elementsCriteria.add(Restrictions.isEmpty("media"));
530
            }
531
        }
532

    
533
        if(features != null && !features.isEmpty()) {
534
            elementsCriteria.add(Restrictions.in("feature", features));
535
        }
536

    
537
        inner.setProjection(Projections.distinct(Projections.id()));
538

    
539
        @SuppressWarnings("unchecked")
540
        List<Object> intermediateResult = inner.list();
541

    
542
        if(intermediateResult.isEmpty()) {
543
            return new ArrayList<>();
544
        }
545

    
546
        Integer[] resultIds = new Integer[intermediateResult.size()];
547
        for(int i = 0; i < resultIds.length; i++) {
548
                resultIds[i] = (Integer)intermediateResult.get(i);
549
        }
550

    
551
        Criteria outer = getCriteria(clazz);
552

    
553
        outer.add(Restrictions.in("id", resultIds));
554
        addOrder(outer, orderHints);
555

    
556
        addPageSizeAndNumber(outer, pageSize, pageNumber);
557

    
558
        @SuppressWarnings({ "unchecked", "rawtypes" })
559
        List<DescriptionBase> results = outer.list();
560
        defaultBeanInitializer.initializeAll(results, propertyPaths);
561
        return results;
562
    }
563

    
564
    @Override
565
    public List<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
566
        checkNotInPriorView("DescriptionDaoImpl.searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTermBase status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths)");
567

    
568
        Criteria criteria = getSession().createCriteria(TaxonDescription.class);
569
        Criteria elements = criteria.createCriteria("descriptionElements", "descriptionElement", Criteria.LEFT_JOIN);
570
        elements.add(Restrictions.in("area", namedAreas.toArray()));
571

    
572
        if(status != null) {
573
            elements.add(Restrictions.eq("status", status));
574
        }
575

    
576
        ProjectionList projectionList = Projections.projectionList().add(Projections.id());
577

    
578
        if(orderHints != null && !orderHints.isEmpty()) {
579
            for(OrderHint orderHint : orderHints) {
580
                projectionList = projectionList.add(Projections.property(orderHint.getPropertyName()));
581
            }
582
        }
583

    
584
        criteria.setProjection(Projections.distinct(projectionList));
585

    
586
        if(pageSize != null) {
587
            criteria.setMaxResults(pageSize);
588
            if(pageNumber != null) {
589
                criteria.setFirstResult(pageNumber * pageSize);
590
            }
591
        }
592

    
593
        addOrder(criteria,orderHints);
594

    
595
        @SuppressWarnings("unchecked")
596
        List<Object> intermediateResult = criteria.list();
597

    
598
        if(intermediateResult.isEmpty()) {
599
            return new ArrayList<>();
600
        }
601

    
602
        Integer[] resultIds = new Integer[intermediateResult.size()];
603
        for(int i = 0; i < resultIds.length; i++) {
604
            if(orderHints == null || orderHints.isEmpty()) {
605
                resultIds[i] = (Integer)intermediateResult.get(i);
606
            } else {
607
              resultIds[i] = ((Number)((Object[])intermediateResult.get(i))[0]).intValue();
608
            }
609
        }
610

    
611
        criteria = getSession().createCriteria(TaxonDescription.class);
612
        criteria.add(Restrictions.in("id", resultIds));
613
        addOrder(criteria,orderHints);
614

    
615
        @SuppressWarnings("unchecked")
616
        List<TaxonDescription> results = criteria.list();
617
        defaultBeanInitializer.initializeAll(results, propertyPaths);
618
        return results;
619
    }
620

    
621
    @Override
622
    public List<CommonTaxonName> searchDescriptionByCommonName(String queryString, MatchMode matchMode, Integer pageSize, Integer pageNumber) {
623

    
624
        Criteria crit = getSession().createCriteria(CommonTaxonName.class);
625
        if (matchMode == MatchMode.EXACT) {
626
            crit.add(Restrictions.eq("name", matchMode.queryStringFrom(queryString)));
627
        } else {
628
            crit.add(Restrictions.ilike("name", matchMode.queryStringFrom(queryString)));
629
        }
630

    
631
        if(pageSize != null) {
632
            crit.setMaxResults(pageSize);
633
            if(pageNumber != null) {
634
                crit.setFirstResult(pageNumber * pageSize);
635
            }
636
        }
637
        @SuppressWarnings("unchecked")
638
        List<CommonTaxonName> results = crit.list();
639
        return results;
640
    }
641

    
642
    @Override
643
    public Integer countDescriptionByCommonName(String queryString, MatchMode matchMode) {
644
        //TODO inprove performance
645
        List<CommonTaxonName> results =  searchDescriptionByCommonName(queryString, matchMode, null, null);
646
        return results.size();
647
    }
648

    
649
    @Override
650
    public DescriptionBase find(LSID lsid) {
651
        DescriptionBase<?> descriptionBase = super.find(lsid);
652
        if(descriptionBase != null) {
653
            List<String> propertyPaths = new ArrayList<>();
654
            propertyPaths.add("createdBy");
655
            propertyPaths.add("updatedBy");
656
            propertyPaths.add("taxon");
657
            propertyPaths.add("taxonName");
658
            propertyPaths.add("descriptionElements");
659
            propertyPaths.add("descriptionElements.createdBy");
660
            propertyPaths.add("descriptionElements.updatedBy");
661
            propertyPaths.add("descriptionElements.feature");
662
            propertyPaths.add("descriptionElements.multilanguageText");
663
            propertyPaths.add("descriptionElements.multilanguageText.language");
664
            propertyPaths.add("descriptionElements.area");
665
            propertyPaths.add("descriptionElements.status");
666
            propertyPaths.add("descriptionElements.modifyingText");
667
            propertyPaths.add("descriptionElementsmodifyingText.language");
668
            propertyPaths.add("descriptionElements.modifiers");
669

    
670
            defaultBeanInitializer.initialize(descriptionBase, propertyPaths);
671
        }
672
        return descriptionBase;
673
    }
674

    
675

    
676
    @Override
677
    public List<Integer> getIndividualAssociationSpecimenIDs(UUID taxonUuid,
678
            Set<Feature> features, Integer pageSize,
679
            Integer pageNumber, List<String> propertyPaths){
680
        Query<Integer> query = prepareGetDescriptionElementForTaxon(taxonUuid, features, IndividualsAssociation.class, pageSize, pageNumber, "de.associatedSpecimenOrObservation.id");
681
        List<Integer> results = query.list();
682
        return results;
683
    }
684

    
685
    @Override
686
    public List<SortableTaxonNodeQueryResult> getNodeOfIndividualAssociationForSpecimen(UUID specimenUuid, UUID classificationUuid){
687
        String selectString = " new " +SortableTaxonNodeQueryResult.class.getName()+"(n.uuid, n.id, n.treeIndex, t.uuid, t.titleCache, t.name.titleCache, t.name.rank, n.parent.uuid) ";
688
        Query<SortableTaxonNodeQueryResult> query = prepareGetIndividualAssociationForSpecimen(specimenUuid, classificationUuid, selectString);
689
        @SuppressWarnings("unchecked")
690
        List<SortableTaxonNodeQueryResult> results = query.list();
691
        return results;
692
    }
693

    
694
    @Override
695
    public <T extends DescriptionElementBase> List<T> getDescriptionElementForTaxon(
696
            UUID taxonUuid, Set<Feature> features,
697
            Class<T> type, Integer pageSize,
698
            Integer pageNumber, List<String> propertyPaths) {
699

    
700
//      LogUtils.setLevel("org.hibernate.SQL", Level.TRACE);
701
        Query<T> query = prepareGetDescriptionElementForTaxon(taxonUuid, features, type, pageSize, pageNumber, "de");
702

    
703
        if (logger.isDebugEnabled()){logger.debug(" dao: get list ...");}
704
        List<T> results = query.list();
705
        if (logger.isDebugEnabled()){logger.debug(" dao: initialize ...");}
706
        defaultBeanInitializer.initializeAll(results, propertyPaths);
707
        if (logger.isDebugEnabled()){logger.debug(" dao: initialize - DONE");}
708

    
709
//      LogUtils.setLevel("org.hibernate.SQL", Level.WARN);
710
        return results;
711
    }
712

    
713
    @Override
714
    public <T extends DescriptionElementBase> long countDescriptionElementForTaxon(
715
            UUID taxonUuid, Set<Feature> features, Class<T> type) {
716

    
717
        Query<Long> query = prepareGetDescriptionElementForTaxon(taxonUuid, features, type, null, null, "count(de)");
718

    
719
        return query.uniqueResult();
720
    }
721

    
722
    private <T extends DescriptionElementBase, R extends Object> Query<R> prepareGetDescriptionElementForTaxon(UUID taxonUuid,
723
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, String selectString) {
724

    
725
        String queryString = "SELECT " + selectString + " FROM DescriptionElementBase AS de" +
726
                " LEFT JOIN de.inDescription AS d" +
727
                " LEFT JOIN d.taxon AS t" +
728
                " WHERE d.class = 'TaxonDescription' AND t.uuid = :taxon_uuid ";
729

    
730
        if(type != null){
731
            queryString += " and de.class = :type";
732
        }
733
        if (features != null && features.size() > 0){
734
            queryString += " and de.feature in (:features) ";
735
        }
736
        Query<R> query = getSession().createQuery(queryString);
737

    
738
        query.setParameter("taxon_uuid", taxonUuid);
739
        if(type != null){
740
            query.setParameter("type", type.getSimpleName());
741
        }
742
        if(features != null && features.size() > 0){
743
            query.setParameterList("features", features) ;
744
        }
745

    
746
        addPageSizeAndNumber(query, pageSize, pageNumber);
747
        return query;
748
    }
749

    
750
    private Query<SortableTaxonNodeQueryResult> prepareGetIndividualAssociationForSpecimen(UUID specimenUuid, UUID classificationUuid, String selectString) {
751

    
752
        String queryString = "SELECT " + selectString + " FROM DescriptionElementBase AS de" +
753
                " LEFT JOIN de.inDescription AS d" +
754
                " LEFT JOIN d.taxon AS t" +
755
                " LEFT JOIN t.taxonNodes AS n" +
756
                " LEFT JOIN de.associatedSpecimenOrObservation AS specimen ";
757
        String classificationString = "";
758
        if (classificationUuid != null){
759
            classificationString = " LEFT JOIN n.classification AS c ";
760
        }
761
        String whereString = " WHERE specimen.uuid = :specimen_uuid";
762
        if (classificationUuid != null){
763
            whereString = whereString + " AND c.uuid = :classifcationUuid";
764
        }
765

    
766
        Query<SortableTaxonNodeQueryResult> query = getSession().createQuery(queryString + classificationString + whereString, SortableTaxonNodeQueryResult.class);
767

    
768
        query.setParameter("specimen_uuid", specimenUuid);
769
        if (classificationUuid != null){
770
            query.setParameter("classifcationUuid", classificationUuid);
771
        }
772

    
773
        return query;
774
    }
775

    
776
    @Override
777
    public List<Media> listTaxonDescriptionMedia(UUID taxonUuid,
778
            Boolean limitToGalleries, Set<MarkerType> markerTypes,
779
            Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
780

    
781
               AuditEvent auditEvent = getAuditEventFromContext();
782
            if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
783
                String queryString = " SELECT media " +
784
                    getTaxonDescriptionMediaQueryString(
785
                        taxonUuid, limitToGalleries,  markerTypes);
786
                queryString +=
787
                    " GROUP BY media "
788
//	    						" ORDER BY index(media) "  //not functional
789
                    ;
790

    
791
                Query<Media> query = getSession().createQuery(queryString, Media.class);
792

    
793
                setTaxonDescriptionMediaParameters(query, taxonUuid, limitToGalleries, markerTypes);
794
//	            addMarkerTypesCriterion(markerTypes, hql);
795

    
796
                addPageSizeAndNumber(query, pageSize, pageNumber);
797
                List<Media> results = query.list();
798
                defaultBeanInitializer.initializeAll(results, propertyPaths);
799

    
800
                return results;
801
            } else {
802
                throw new OperationNotSupportedInPriorViewException("countTaxonDescriptionMedia(UUID taxonUuid, boolean restrictToGalleries)");
803
            }
804
    }
805

    
806
    @Override
807
    public int countTaxonDescriptionMedia(UUID taxonUuid,
808
            Boolean limitToGalleries, Set<MarkerType> markerTypes) {
809
        AuditEvent auditEvent = getAuditEventFromContext();
810
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
811
            String queryString = " SELECT count(DISTINCT media) " +
812
                getTaxonDescriptionMediaQueryString(
813
                    taxonUuid, limitToGalleries, markerTypes);
814

    
815
            Query<Long> query = getSession().createQuery(queryString, Long.class);
816
            setTaxonDescriptionMediaParameters(query, taxonUuid, limitToGalleries, markerTypes);
817
            return query.uniqueResult().intValue();
818
        }else{
819
            throw new OperationNotSupportedInPriorViewException("countTaxonDescriptionMedia(UUID taxonUuid)");
820
        }
821

    
822
    }
823

    
824
    private void setTaxonDescriptionMediaParameters(Query query, UUID taxonUuid, Boolean limitToGalleries, Set<MarkerType> markerTypes) {
825
        if(taxonUuid != null){
826
            query.setParameter("uuid", taxonUuid);
827
        }
828
    }
829

    
830
    /**
831
     * @param taxonUuid
832
     * @param restrictToGalleries
833
     * @param markerTypes
834
     * @return
835
     */
836
    private String getTaxonDescriptionMediaQueryString(UUID taxonUuid,
837
            Boolean restrictToGalleries, Set<MarkerType> markerTypes) {
838
        String fromQueryString =
839
            " FROM DescriptionElementBase as deb INNER JOIN " +
840
                " deb.inDescription as td "
841
                + " INNER JOIN td.taxon as t "
842
                + " JOIN deb.media as media "
843
                + " LEFT JOIN td.markers marker ";
844

    
845
        String whereQueryString = " WHERE (1=1) ";
846
        if (taxonUuid != null){
847
            whereQueryString += " AND t.uuid = :uuid ";
848
        }
849
        if (restrictToGalleries){
850
            whereQueryString += " AND td.imageGallery is true ";
851
        }
852
        if (markerTypes != null && !markerTypes.isEmpty()){
853
            whereQueryString += " AND (1=0";
854
            for (MarkerType markerType : markerTypes){
855
                whereQueryString += " OR ( marker.markerType.id = " + markerType.getId() + " AND marker.flag is true)";
856

    
857
            }
858
            whereQueryString += ") ";
859
        }
860

    
861
        return fromQueryString + whereQueryString;
862

    
863
    }
864

    
865
    @SuppressWarnings("unchecked")
866
    @Override
867
    public List<TermDto> listNamedAreasInUse(boolean includeAllParents, Integer pageSize, Integer pageNumber) {
868

    
869
//      LogUtils.setLevel("org.hibernate.SQL", Level.TRACE);
870

    
871
        StringBuilder queryString = new StringBuilder(
872
                "SELECT DISTINCT a.id, a.partOf.id"
873
                + " FROM Distribution AS d JOIN d.area AS a");
874
        Query<Object[]> query = getSession().createQuery(queryString.toString(), Object[].class);
875

    
876
        List<Object[]> areasInUse = query.list();
877
        List<Object[]> parentResults = new ArrayList<>();
878

    
879
        if(!areasInUse.isEmpty()) {
880
            Set<Object> allAreaIds = new HashSet<>(areasInUse.size());
881

    
882
            if(includeAllParents) {
883
                // find all parent nodes
884
                String allAreasQueryStr = "select a.id, a.partOf.id from NamedArea as a";
885
                query = getSession().createQuery(allAreasQueryStr, Object[].class);
886
                List<Object[]> allAreasResult = query.list();
887
                Map<Object, Object> allAreasMap = ArrayUtils.toMap(allAreasResult.toArray());
888

    
889
                Set<Object> parents = new HashSet<>();
890

    
891
                for(Object[] leaf : areasInUse) {
892
                    allAreaIds.add(leaf[0]);
893
                    Object parentId = leaf[1];
894
                    while (parentId != null) {
895
                        if(parents.contains(parentId)) {
896
                            // break if the parent already is in the set
897
                            break;
898
                        }
899
                        parents.add(parentId);
900
                        parentId = allAreasMap.get(parentId);
901
                    }
902
                }
903
                allAreaIds.addAll(parents);
904
            } else {
905
                // only add the ids found so far
906
                for(Object[] leaf : areasInUse) {
907
                    allAreaIds.add(leaf[0]);
908
                }
909
            }
910

    
911
            // NOTE can't use "select new TermDto(distinct a.uuid, r , a.vocabulary.uuid) since we will get multiple
912
            // rows for a term with multiple representations
913
            String parentAreasQueryStr = TermDto.getTermDtoSelect("NamedArea")
914
                    + "where a.id in (:allAreaIds) order by a.idInVocabulary";
915
            query = getSession().createQuery(parentAreasQueryStr, Object[].class);
916
            query.setParameterList("allAreaIds", allAreaIds);
917

    
918
            addPageSizeAndNumber(query, pageSize, pageNumber);
919
            parentResults = query.list();
920
        }
921
        List<TermDto> dtoList = TermDto.termDtoListFrom(parentResults);
922

    
923
        return dtoList;
924
    }
925

    
926

    
927

    
928

    
929

    
930
}
(1-1/7)