Project

General

Profile

Download (38.6 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.HashMap;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Set;
18
import java.util.UUID;
19

    
20
import org.apache.commons.lang.ArrayUtils;
21
import org.apache.log4j.Logger;
22
import org.hibernate.Criteria;
23
import org.hibernate.Query;
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.springframework.beans.factory.annotation.Qualifier;
30
import org.springframework.stereotype.Repository;
31

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

    
56
@Repository
57
@Qualifier("descriptionDaoImpl")
58
public class DescriptionDaoImpl extends IdentifiableDaoBase<DescriptionBase> implements IDescriptionDao{
59

    
60
    private static final Logger logger = Logger.getLogger(DescriptionDaoImpl.class);
61

    
62
    public DescriptionDaoImpl() {
63
        super(DescriptionBase.class);
64
        indexedClasses = new Class[3];
65
        indexedClasses[0] = TaxonDescription.class;
66
        indexedClasses[1] = TaxonNameDescription.class;
67
        indexedClasses[2] = SpecimenDescription.class;
68
    }
69

    
70
//    @Override  //Override for testing
71
//    public DescriptionBase load(UUID uuid, List<String> propertyPaths){
72
//    	DescriptionBase bean = findByUuid(uuid);
73
//        if(bean == null){
74
//            return bean;
75
//        }
76
//        defaultBeanInitializer.initialize(bean, propertyPaths);
77
//
78
//        return bean;
79
//    }
80

    
81
    @Override
82
    public int countDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm status) {
83
        checkNotInPriorView("DescriptionDaoImpl.countDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTermBase status)");
84
        Query query = null;
85

    
86
        if(status == null) {
87
            query = getSession().createQuery("select count(distinct description) from TaxonDescription description left join description.descriptionElements element join element.area area where area in (:namedAreas)");
88
        } else {
89
            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");
90
            query.setParameter("status", status);
91
        }
92
        query.setParameterList("namedAreas", namedAreas);
93

    
94
        return ((Long)query.uniqueResult()).intValue();
95
    }
96

    
97
    @Override
98
    public <T extends DescriptionElementBase> int countDescriptionElements(DescriptionBase description, Set<Feature> features, Class<T> clazz) {
99
        return countDescriptionElements(description, null, features, clazz);
100
    }
101

    
102
    @Override
103
    public <T extends DescriptionElementBase> int countDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
104
            Set<Feature> features, Class<T> clazz) {
105
        AuditEvent auditEvent = getAuditEventFromContext();
106
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
107
            Criteria criteria = null;
108
            if(clazz == null) {
109
                criteria = getSession().createCriteria(DescriptionElementBase.class);
110
            } else {
111
                criteria = getSession().createCriteria(clazz);
112
            }
113

    
114
            if(description != null) {
115
                criteria.add(Restrictions.eq("inDescription", description));
116
            }
117

    
118
            if(descriptionType != null) {
119
                criteria.createAlias("inDescription", "d").add(Restrictions.eq("d.class", descriptionType));
120
            }
121

    
122
            if(features != null && !features.isEmpty()) {
123
                criteria.add(Restrictions.in("feature", features));
124
            }
125

    
126
            criteria.setProjection(Projections.rowCount());
127

    
128
            return ((Number)criteria.uniqueResult()).intValue();
129
        } else {
130
            if(features != null && !features.isEmpty()) {
131
                Integer count = 0;
132
                for(Feature f : features) {
133
                    AuditQuery query = null;
134
                    if(clazz == null) {
135
                        query = getAuditReader().createQuery().forEntitiesAtRevision(DescriptionElementBase.class,auditEvent.getRevisionNumber());
136
                    } else {
137
                        query = getAuditReader().createQuery().forEntitiesAtRevision(clazz,auditEvent.getRevisionNumber());
138
                    }
139

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

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

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

    
153
                return count;
154
            } else {
155
                AuditQuery query = null;
156
                if(clazz == null) {
157
                    query = getAuditReader().createQuery().forEntitiesAtRevision(DescriptionElementBase.class,auditEvent.getRevisionNumber());
158
                } else {
159
                    query = getAuditReader().createQuery().forEntitiesAtRevision(clazz,auditEvent.getRevisionNumber());
160
                }
161

    
162
                if(description != null) {
163
                    query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
164
                }
165
                if(descriptionType != null) {
166
                    query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
167
                }
168

    
169
                query.addProjection(AuditEntity.id().count());
170
                return ((Long)query.getSingleResult()).intValue();
171
            }
172
        }
173
    }
174

    
175
    @Override
176
    public int countDescriptions(Class<? extends DescriptionBase> clazz, Boolean hasImages, Boolean hasText, Set<Feature> features) {
177
        checkNotInPriorView("DescriptionDaoImpl.countDescriptions(Class<TYPE> type, Boolean hasImages, Boolean hasText, Set<Feature> features)");
178
        Criteria inner = null;
179

    
180
        if(clazz == null) {
181
            inner = getSession().createCriteria(type);
182
        } else {
183
            inner = getSession().createCriteria(clazz);
184
        }
185

    
186
        Criteria elementsCriteria = inner.createCriteria("descriptionElements");
187
        if(hasText != null) {
188
            if(hasText) {
189
                elementsCriteria.add(Restrictions.isNotEmpty("multilanguageText"));
190
            } else {
191
                elementsCriteria.add(Restrictions.isEmpty("multilanguageText"));
192
            }
193
        }
194

    
195
        if(hasImages != null) {
196
            if(hasImages) {
197
                elementsCriteria.add(Restrictions.isNotEmpty("media"));
198
            } else {
199
                elementsCriteria.add(Restrictions.isEmpty("media"));
200
            }
201
        }
202

    
203
        if(features != null && !features.isEmpty()) {
204
            elementsCriteria.add(Restrictions.in("feature", features));
205
        }
206

    
207
        inner.setProjection(Projections.countDistinct("id"));
208

    
209
        return ((Number) inner.uniqueResult()).intValue();
210
    }
211

    
212
    @Override
213
    public int countTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes,Set<NamedArea> geographicalScopes, Set<MarkerType> markerTypes) {
214
        AuditEvent auditEvent = getAuditEventFromContext();
215
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
216
            Criteria criteria = getSession().createCriteria(TaxonDescription.class);
217

    
218
            if(taxon != null) {
219
                criteria.add(Restrictions.eq("taxon", taxon));
220
            }
221

    
222
            if(scopes != null && !scopes.isEmpty()) {
223
                Set<Integer> scopeIds = new HashSet<Integer>();
224
                for(DefinedTerm s : scopes) {
225
                    scopeIds.add(s.getId());
226
                }
227
                criteria.createCriteria("scopes").add(Restrictions.in("id", scopeIds));
228
            }
229

    
230
            if(geographicalScopes != null && !geographicalScopes.isEmpty()) {
231
                Set<Integer> geoScopeIds = new HashSet<Integer>();
232
                for(NamedArea n : geographicalScopes) {
233
                    geoScopeIds.add(n.getId());
234
                }
235
                criteria.createCriteria("geoScopes").add(Restrictions.in("id", geoScopeIds));
236
            }
237

    
238

    
239
            addMarkerTypesCriterion(markerTypes, criteria);
240

    
241

    
242
            criteria.setProjection(Projections.rowCount());
243

    
244
            return ((Number)criteria.uniqueResult()).intValue();
245
        } else {
246
            if((scopes == null || scopes.isEmpty())&& (geographicalScopes == null || geographicalScopes.isEmpty()) && (markerTypes == null || markerTypes.isEmpty())) {
247
                AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonDescription.class,auditEvent.getRevisionNumber());
248
                if(taxon != null) {
249
                    query.add(AuditEntity.relatedId("taxon").eq(taxon.getId()));
250
                }
251

    
252
                query.addProjection(AuditEntity.id().count());
253

    
254
                return ((Long)query.getSingleResult()).intValue();
255
            } else {
256
                throw new OperationNotSupportedInPriorViewException("countTaxonDescriptions(Taxon taxon, Set<Scope> scopes,Set<NamedArea> geographicalScopes)");
257
            }
258
        }
259
    }
260

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

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

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

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

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

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

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

    
322
            List<T> results = criteria.list();
323

    
324
            defaultBeanInitializer.initializeAll(results, propertyPaths);
325

    
326
            return results;
327
        } else {
328
            List<T> result = new ArrayList<T>();
329
            if(features != null && !features.isEmpty()) {
330

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

    
339
                    if(description != null) {
340
                        query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
341
                    }
342

    
343
                    if(descriptionType != null) {
344
                        query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
345
                    }
346

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

    
358
                if(description != null) {
359
                    query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
360
                }
361

    
362
                if(descriptionType != null) {
363
                    query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
364
                }
365

    
366
                result = query.getResultList();
367
            }
368

    
369
            defaultBeanInitializer.initializeAll(result, propertyPaths);
370

    
371
            return result;
372
        }
373
    }
374

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

    
381
            if(taxon != null) {
382
                criteria.add(Restrictions.eq("taxon", taxon));
383
            }
384

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

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

    
401
            addMarkerTypesCriterion(markerTypes, criteria);
402

    
403
            if(pageSize != null) {
404
                criteria.setMaxResults(pageSize);
405
                if(pageNumber != null) {
406
                    criteria.setFirstResult(pageNumber * pageSize);
407
                }
408
            }
409

    
410
            List<TaxonDescription> results = criteria.list();
411

    
412
            defaultBeanInitializer.initializeAll(results, propertyPaths);
413

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

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

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

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

    
446
          if(name != null) {
447
              criteria.add(Restrictions.eq("taxonName", name));
448
          }
449

    
450
          if(pageSize != null) {
451
              criteria.setMaxResults(pageSize);
452
              if(pageNumber != null) {
453
                  criteria.setFirstResult(pageNumber * pageSize);
454
              }
455
          }
456

    
457
          List<TaxonNameDescription> results = criteria.list();
458

    
459
          defaultBeanInitializer.initializeAll(results, propertyPaths);
460

    
461
          return results;
462
        } else {
463
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonNameDescription.class,auditEvent.getRevisionNumber());
464

    
465
            if(name != null) {
466
                query.add(AuditEntity.relatedId("taxonName").eq(name.getId()));
467
            }
468

    
469
            if(pageSize != null) {
470
                  query.setMaxResults(pageSize);
471
                  if(pageNumber != null) {
472
                      query.setFirstResult(pageNumber * pageSize);
473
                  }
474
            }
475

    
476
            List<TaxonNameDescription> results = query.getResultList();
477

    
478
            defaultBeanInitializer.initializeAll(results, propertyPaths);
479

    
480
            return results;
481
        }
482

    
483
    }
484

    
485
    @Override
486
    public int countTaxonNameDescriptions(TaxonNameBase name) {
487
        AuditEvent auditEvent = getAuditEventFromContext();
488
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
489
            Criteria criteria = getSession().createCriteria(TaxonNameDescription.class);
490

    
491
            if(name != null) {
492
                criteria.add(Restrictions.eq("taxonName", name));
493
            }
494

    
495
            criteria.setProjection(Projections.rowCount());
496

    
497
            return ((Number)criteria.uniqueResult()).intValue();
498
        } else {
499
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonNameDescription.class,auditEvent.getRevisionNumber());
500

    
501
            if(name != null) {
502
                query.add(AuditEntity.relatedId("taxonName").eq(name.getId()));
503
            }
504

    
505
            query.addProjection(AuditEntity.id().count());
506
            return ((Long)query.getSingleResult()).intValue();
507
        }
508
    }
509

    
510
    /**
511
     * Should use a DetachedCriteria & subquery, but HHH-158 prevents this, for now.
512
     *
513
     * e.g. DetachedCriteria inner = DestachedCriteria.forClass(type);
514
     *
515
     * outer.add(Subqueries.propertyIn("id", inner));
516
     */
517
    @Override
518
    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) {
519
        checkNotInPriorView("DescriptionDaoImpl.listDescriptions(Class<TYPE> type, Boolean hasImages, Boolean hasText,	Set<Feature> features, Integer pageSize, Integer pageNumber)");
520
        Criteria inner = null;
521

    
522
        if(clazz == null) {
523
            inner = getSession().createCriteria(type);
524
        } else {
525
            inner = getSession().createCriteria(clazz);
526
        }
527

    
528
        Criteria elementsCriteria = inner.createCriteria("descriptionElements");
529
        if(hasText != null) {
530
            if(hasText) {
531
                elementsCriteria.add(Restrictions.isNotEmpty("multilanguageText"));
532
            } else {
533
                elementsCriteria.add(Restrictions.isEmpty("multilanguageText"));
534
            }
535
        }
536

    
537
        if(hasImages != null) {
538
            if(hasImages) {
539
                elementsCriteria.add(Restrictions.isNotEmpty("media"));
540
            } else {
541
                elementsCriteria.add(Restrictions.isEmpty("media"));
542
            }
543
        }
544

    
545
        if(features != null && !features.isEmpty()) {
546
            elementsCriteria.add(Restrictions.in("feature", features));
547
        }
548

    
549
        inner.setProjection(Projections.distinct(Projections.id()));
550

    
551
        List<Object> intermediateResult = inner.list();
552

    
553
        if(intermediateResult.isEmpty()) {
554
            return new ArrayList<DescriptionBase>();
555
        }
556

    
557
        Integer[] resultIds = new Integer[intermediateResult.size()];
558
        for(int i = 0; i < resultIds.length; i++) {
559
                resultIds[i] = ((Number)intermediateResult.get(i)).intValue();
560
        }
561

    
562
        Criteria outer = null;
563

    
564
        if(clazz == null) {
565
            outer = getSession().createCriteria(type);
566
        } else {
567
            outer = getSession().createCriteria(clazz);
568
        }
569

    
570
        outer.add(Restrictions.in("id", resultIds));
571
        addOrder(outer, orderHints);
572

    
573
        if(pageSize != null) {
574
            outer.setMaxResults(pageSize);
575
            if(pageNumber != null) {
576
                outer.setFirstResult(pageNumber * pageSize);
577
            }
578
        }
579

    
580
        List<DescriptionBase> results = outer.list();
581
        defaultBeanInitializer.initializeAll(results, propertyPaths);
582
        return results;
583
    }
584

    
585
    @Override
586
    public List<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
587
        checkNotInPriorView("DescriptionDaoImpl.searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTermBase status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths)");
588

    
589
        Criteria criteria = getSession().createCriteria(TaxonDescription.class);
590
        Criteria elements = criteria.createCriteria("descriptionElements", "descriptionElement", Criteria.LEFT_JOIN);
591
        elements.add(Restrictions.in("area", namedAreas.toArray()));
592

    
593
        if(status != null) {
594
            elements.add(Restrictions.eq("status", status));
595
        }
596

    
597
        ProjectionList projectionList = Projections.projectionList().add(Projections.id());
598

    
599
        if(orderHints != null && !orderHints.isEmpty()) {
600
            for(OrderHint orderHint : orderHints) {
601
                projectionList = projectionList.add(Projections.property(orderHint.getPropertyName()));
602
            }
603
        }
604

    
605
        criteria.setProjection(Projections.distinct(projectionList));
606

    
607
        if(pageSize != null) {
608
            criteria.setMaxResults(pageSize);
609
            if(pageNumber != null) {
610
                criteria.setFirstResult(pageNumber * pageSize);
611
            }
612
        }
613

    
614
        addOrder(criteria,orderHints);
615

    
616
        List<Object> intermediateResult = criteria.list();
617

    
618
        if(intermediateResult.isEmpty()) {
619
            return new ArrayList<TaxonDescription>();
620
        }
621

    
622
        Integer[] resultIds = new Integer[intermediateResult.size()];
623
        for(int i = 0; i < resultIds.length; i++) {
624
            if(orderHints == null || orderHints.isEmpty()) {
625
                resultIds[i] = ((Number)intermediateResult.get(i)).intValue();
626
            } else {
627
              resultIds[i] = ((Number)((Object[])intermediateResult.get(i))[0]).intValue();
628
            }
629
        }
630

    
631
        criteria = getSession().createCriteria(TaxonDescription.class);
632
        criteria.add(Restrictions.in("id", resultIds));
633
        addOrder(criteria,orderHints);
634

    
635
        List<TaxonDescription> results = criteria.list();
636
        defaultBeanInitializer.initializeAll(results, propertyPaths);
637
        return results;
638
    }
639

    
640
    @Override
641
    public List<CommonTaxonName> searchDescriptionByCommonName(String queryString, MatchMode matchMode, Integer pageSize, Integer pageNumber) {
642

    
643
        Criteria crit = getSession().createCriteria(CommonTaxonName.class);
644
        if (matchMode == MatchMode.EXACT) {
645
            crit.add(Restrictions.eq("name", matchMode.queryStringFrom(queryString)));
646
        } else {
647
            crit.add(Restrictions.ilike("name", matchMode.queryStringFrom(queryString)));
648
        }
649

    
650
        if(pageSize != null) {
651
            crit.setMaxResults(pageSize);
652
            if(pageNumber != null) {
653
                crit.setFirstResult(pageNumber * pageSize);
654
            }
655
        }
656
        List<CommonTaxonName> results = crit.list();
657
        return results;
658
    }
659

    
660
    @Override
661
    public Integer countDescriptionByCommonName(String queryString, MatchMode matchMode) {
662
        //TODO inprove performance
663
        List<CommonTaxonName> results =  searchDescriptionByCommonName(queryString, matchMode, null, null);
664
        return results.size();
665
    }
666

    
667
    @Override
668
    public DescriptionBase find(LSID lsid) {
669
        DescriptionBase descriptionBase = super.find(lsid);
670
        if(descriptionBase != null) {
671
            List<String> propertyPaths = new ArrayList<String>();
672
            propertyPaths.add("createdBy");
673
            propertyPaths.add("updatedBy");
674
            propertyPaths.add("taxon");
675
            propertyPaths.add("taxonName");
676
            propertyPaths.add("descriptionElements");
677
            propertyPaths.add("descriptionElements.createdBy");
678
            propertyPaths.add("descriptionElements.updatedBy");
679
            propertyPaths.add("descriptionElements.feature");
680
            propertyPaths.add("descriptionElements.multilanguageText");
681
            propertyPaths.add("descriptionElements.multilanguageText.language");
682
            propertyPaths.add("descriptionElements.area");
683
            propertyPaths.add("descriptionElements.status");
684
            propertyPaths.add("descriptionElements.modifyingText");
685
            propertyPaths.add("descriptionElementsmodifyingText.language");
686
            propertyPaths.add("descriptionElements.modifiers");
687

    
688
            defaultBeanInitializer.initialize(descriptionBase, propertyPaths);
689
        }
690
        return descriptionBase;
691
    }
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
//        Logger.getLogger("org.hibernate.SQL").setLevel(Level.TRACE);
701

    
702
        Query query = prepareGetDescriptionElementForTaxon(taxonUuid, features, type, pageSize, pageNumber, false);
703

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

    
711
//        Logger.getLogger("org.hibernate.SQL").setLevel(Level.WARN);
712
        return results;
713
    }
714

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

    
719
        Query query = prepareGetDescriptionElementForTaxon(taxonUuid, features, type, null, null, true);
720

    
721
        return (Long)query.uniqueResult();
722
    }
723

    
724
    /**
725
     * @param taxon
726
     * @param features
727
     * @param type
728
     * @param pageSize
729
     * @param pageNumber
730
     * @return
731
     */
732
    private <T extends DescriptionElementBase> Query prepareGetDescriptionElementForTaxon(UUID taxonUuid,
733
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, boolean asCountQuery) {
734

    
735
        String listOrCount;
736
        if(asCountQuery){
737
            listOrCount = "count(de)";
738
        } else {
739
            listOrCount = "de";
740
        }
741

    
742
        String queryString = "SELECT " + listOrCount + " FROM DescriptionElementBase AS de" +
743
                " LEFT JOIN de.inDescription AS d" +
744
                " LEFT JOIN d.taxon AS t" +
745
                " WHERE d.class = 'TaxonDescription' AND t.uuid = :taxon_uuid ";
746

    
747
        if(type != null){
748
            queryString += " and de.class = :type";
749
        }
750
        if (features != null && features.size() > 0){
751
            queryString += " and de.feature in (:features) ";
752
        }
753
//		System.out.println(queryString);
754
        Query query = getSession().createQuery(queryString);
755

    
756
        query.setParameter("taxon_uuid", taxonUuid);
757
        if(type != null){
758
            query.setParameter("type", type.getSimpleName());
759
        }
760
        if(features != null && features.size() > 0){
761
            query.setParameterList("features", features) ;
762
        }
763

    
764
        if(pageSize != null) {
765
            query.setMaxResults(pageSize);
766
            if(pageNumber != null) {
767
                query.setFirstResult(pageNumber * pageSize);
768
            }
769
        }
770
        return query;
771
    }
772

    
773
    /* (non-Javadoc)
774
     * @see eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao#listTaxonDescriptionMedia(java.util.UUID, java.lang.Boolean, java.util.Set, java.lang.Integer, java.lang.Integer, java.util.List)
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 query = getSession().createQuery(queryString);
792

    
793
                setTaxonDescriptionMediaParameters(query, taxonUuid, limitToGalleries, markerTypes);
794

    
795

    
796
//	            addMarkerTypesCriterion(markerTypes, hql);
797

    
798
                setPagingParameter(query, pageSize, pageNumber);
799

    
800
                List<Media> results = query.list();
801

    
802
                defaultBeanInitializer.initializeAll(results, propertyPaths);
803

    
804
                return results;
805
            } else {
806
                throw new OperationNotSupportedInPriorViewException("countTaxonDescriptionMedia(UUID taxonUuid, boolean restrictToGalleries)");
807
            }
808
    }
809

    
810

    
811
    /* (non-Javadoc)
812
     * @see eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao#countTaxonDescriptionMedia(java.util.UUID, java.lang.Boolean, java.util.Set)
813
     */
814
    @Override
815
    public int countTaxonDescriptionMedia(UUID taxonUuid,
816
            Boolean limitToGalleries, Set<MarkerType> markerTypes) {
817
        AuditEvent auditEvent = getAuditEventFromContext();
818
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
819
            String queryString = " SELECT count(DISTINCT media) " +
820
                getTaxonDescriptionMediaQueryString(
821
                    taxonUuid, limitToGalleries, markerTypes);
822

    
823
            Query query = getSession().createQuery(queryString);
824
            setTaxonDescriptionMediaParameters(query, taxonUuid, limitToGalleries, markerTypes);
825
            return ((Long)query.uniqueResult()).intValue();
826
        }else{
827
            throw new OperationNotSupportedInPriorViewException("countTaxonDescriptionMedia(UUID taxonUuid)");
828
        }
829

    
830
    }
831

    
832
    private void setTaxonDescriptionMediaParameters(Query query, UUID taxonUuid, Boolean limitToGalleries, Set<MarkerType> markerTypes) {
833
        if(taxonUuid != null){
834
            query.setParameter("uuid", taxonUuid);
835
        }
836

    
837
    }
838

    
839
    /**
840
     * @param taxonUuid
841
     * @param restrictToGalleries
842
     * @param markerTypes
843
     * @return
844
     */
845
    private String getTaxonDescriptionMediaQueryString(UUID taxonUuid,
846
            Boolean restrictToGalleries, Set<MarkerType> markerTypes) {
847
        String fromQueryString =
848
            " FROM DescriptionElementBase as deb INNER JOIN " +
849
                " deb.inDescription as td "
850
                + " INNER JOIN td.taxon as t "
851
                + " JOIN deb.media as media "
852
                + " LEFT JOIN td.markers marker ";
853

    
854
        String whereQueryString = " WHERE (1=1) ";
855
        if (taxonUuid != null){
856
            whereQueryString += " AND t.uuid = :uuid ";
857
        }
858
        if (restrictToGalleries){
859
            whereQueryString += " AND td.imageGallery is true ";
860
        }
861
        if (markerTypes != null && !markerTypes.isEmpty()){
862
            whereQueryString += " AND (1=0";
863
            for (MarkerType markerType : markerTypes){
864
                whereQueryString += " OR ( marker.markerType.id = " + markerType.getId() + " AND marker.flag is true)";
865

    
866
            }
867
            whereQueryString += ") ";
868
        }
869

    
870
        return fromQueryString + whereQueryString;
871

    
872
    }
873

    
874
    /* (non-Javadoc)
875
     * @see eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao#listNamedAreasInUse(java.lang.Integer, java.lang.Integer, java.util.List)
876
     */
877
    @SuppressWarnings("unchecked")
878
    @Override
879
    public List<TermDto> listNamedAreasInUse(boolean includeAllParents, Integer pageSize, Integer pageNumber) {
880

    
881
//        Logger.getLogger("org.hibernate.SQL").setLevel(Level.TRACE);
882

    
883
        StringBuilder queryString = new StringBuilder(
884
                "SELECT DISTINCT a.id, a.partOf.id"
885
                + " FROM Distribution AS d JOIN d.area AS a");
886
        Query query = getSession().createQuery(queryString.toString());
887

    
888
        List<Object[]> areasInUse = query.list();
889
        List<Object[]> parentResults = new ArrayList<Object[]>();
890

    
891
        if(!areasInUse.isEmpty()) {
892
            Set<Object> allAreaIds = new HashSet<Object>(areasInUse.size());
893

    
894
            if(includeAllParents) {
895
                // find all parent nodes
896
                String allAreasQueryStr = "select a.id, a.partOf.id from NamedArea as a";
897
                query = getSession().createQuery(allAreasQueryStr);
898
                List<Object[]> allAreasResult = query.list();
899
                Map<Object, Object> allAreasMap = ArrayUtils.toMap(allAreasResult.toArray());
900

    
901
                Set<Object> parents = new HashSet<Object>();
902

    
903
                for(Object[] leaf : areasInUse) {
904
                    allAreaIds.add(leaf[0]);
905
                    Object parentId = leaf[1];
906
                    while (parentId != null) {
907
                        if(parents.contains(parentId)) {
908
                            // break if the parent already is in the set
909
                            break;
910
                        }
911
                        parents.add(parentId);
912
                        parentId = allAreasMap.get(parentId);
913
                    }
914
                }
915
                allAreaIds.addAll(parents);
916
            } else {
917
                // only add the ids found so far
918
                for(Object[] leaf : areasInUse) {
919
                    allAreaIds.add(leaf[0]);
920
                }
921
            }
922

    
923

    
924
            // NOTE can't use "select new TermDto(distinct a.uuid, r , a.vocabulary.uuid) since we will get multiple
925
            // rows for a term with multiple representations
926
            String parentAreasQueryStr = "select a.uuid, r, p.uuid, v.uuid, a.orderIndex "
927
                    + "from NamedArea as a LEFT JOIN a.partOf as p LEFT JOIN a.representations AS r LEFT JOIN a.vocabulary as v "
928
                    + "where a.id in (:allAreaIds) order by a.idInVocabulary";
929
            query = getSession().createQuery(parentAreasQueryStr);
930
            query.setParameterList("allAreaIds", allAreaIds);
931
            if(pageSize != null) {
932
                query.setMaxResults(pageSize);
933
                if(pageNumber != null) {
934
                    query.setFirstResult(pageNumber * pageSize);
935
                }
936
            }
937
            parentResults = query.list();
938
        }
939
        List<TermDto> dtoList = termDtoListFrom(parentResults);
940

    
941
        return dtoList;
942
    }
943

    
944
    /**
945
     * @param results
946
     * @return
947
     */
948
    private List<TermDto> termDtoListFrom(List<Object[]> results) {
949
        Map<UUID, TermDto> dtoMap = new HashMap<UUID, TermDto>(results.size());
950
        for (Object[] elements : results) {
951
            UUID uuid = (UUID)elements[0];
952
            if(dtoMap.containsKey(uuid)){
953
                dtoMap.get(uuid).addRepresentation((Representation)elements[1]);
954
            } else {
955
                Set<Representation> representations;
956
                if(elements[1] instanceof Representation) {
957
                    representations = new HashSet<Representation>(1);
958
                    representations.add((Representation)elements[1]);
959
                } else {
960
                    representations = (Set<Representation>)elements[1];
961
                }
962
                dtoMap.put(uuid, new TermDto(uuid, representations, (UUID)elements[2], (UUID)elements[3], (Integer)elements[4]));
963
            }
964
        }
965
        return new ArrayList<TermDto>(dtoMap.values());
966
    }
967

    
968

    
969

    
970
}
(1-1/10)