Project

General

Profile

Download (43.1 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2008 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*/
6

    
7
package eu.etaxonomy.cdm.persistence.dao.hibernate.occurrence;
8

    
9
import java.util.ArrayList;
10
import java.util.Collection;
11
import java.util.Collections;
12
import java.util.HashSet;
13
import java.util.List;
14
import java.util.Set;
15
import java.util.UUID;
16

    
17
import org.apache.log4j.Logger;
18
import org.hibernate.Criteria;
19
import org.hibernate.Hibernate;
20
import org.hibernate.Query;
21
import org.hibernate.Session;
22
import org.hibernate.criterion.Disjunction;
23
import org.hibernate.criterion.ProjectionList;
24
import org.hibernate.criterion.Projections;
25
import org.hibernate.criterion.Restrictions;
26
import org.hibernate.envers.query.AuditEntity;
27
import org.hibernate.envers.query.AuditQuery;
28
import org.hibernate.search.FullTextSession;
29
import org.hibernate.search.Search;
30
import org.springframework.beans.factory.annotation.Autowired;
31
import org.springframework.stereotype.Repository;
32

    
33
import eu.etaxonomy.cdm.model.common.CdmBase;
34
import eu.etaxonomy.cdm.model.description.DescriptionBase;
35
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
36
import eu.etaxonomy.cdm.model.media.Media;
37
import eu.etaxonomy.cdm.model.molecular.DnaSample;
38
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
39
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
40
import eu.etaxonomy.cdm.model.name.TaxonName;
41
import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
42
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
43
import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
44
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
45
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
46
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
47
import eu.etaxonomy.cdm.model.taxon.Synonym;
48
import eu.etaxonomy.cdm.model.taxon.Taxon;
49
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
50
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
51
import eu.etaxonomy.cdm.model.view.AuditEvent;
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.dao.hibernate.taxon.TaxonDaoHibernateImpl;
55
import eu.etaxonomy.cdm.persistence.dao.name.IHomotypicalGroupDao;
56
import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
57
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
58
import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
59
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
60
import eu.etaxonomy.cdm.persistence.query.MatchMode;
61
import eu.etaxonomy.cdm.persistence.query.OrderHint;
62

    
63
/**
64
 * @author a.babadshanjan
65
 * @since 01.09.2008
66
 */
67
@Repository
68
public class OccurrenceDaoHibernateImpl
69
          extends IdentifiableDaoBase<SpecimenOrObservationBase>
70
          implements IOccurrenceDao {
71

    
72
    @SuppressWarnings("unused")
73
    private static final Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);
74

    
75
    @Autowired
76
    private IDescriptionDao descriptionDao;
77

    
78
    @Autowired
79
    private ITaxonNameDao taxonNameDao;
80

    
81
    @Autowired
82
    private IHomotypicalGroupDao homotypicalGroupDao;
83

    
84
    public OccurrenceDaoHibernateImpl() {
85
        super(SpecimenOrObservationBase.class);
86
        indexedClasses = new Class[7];
87
        indexedClasses[0] = FieldUnit.class;
88
        indexedClasses[1] = DerivedUnit.class;
89
        indexedClasses[5] = DnaSample.class;
90
    }
91

    
92
    @Override
93
    public int countDerivationEvents(SpecimenOrObservationBase occurence) {
94
        checkNotInPriorView("OccurrenceDaoHibernateImpl.countDerivationEvents(SpecimenOrObservationBase occurence)");
95
        Query query = getSession().createQuery("select count(distinct derivationEvent) from DerivationEvent derivationEvent join derivationEvent.originals occurence where occurence = :occurence");
96
        query.setParameter("occurence", occurence);
97

    
98
        return ((Long)query.uniqueResult()).intValue();
99
    }
100

    
101
    @Override
102
    public int countDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase) {
103
        AuditEvent auditEvent = getAuditEventFromContext();
104
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
105
            Criteria criteria = getSession().createCriteria(DeterminationEvent.class);
106
            if(occurrence != null) {
107
                criteria.add(Restrictions.eq("identifiedUnit",occurrence));
108
            }
109

    
110
            if(taxonBase != null) {
111
                criteria.add(Restrictions.eq("taxon",taxonBase));
112
            }
113

    
114
            criteria.setProjection(Projections.rowCount());
115
            return ((Number)criteria.uniqueResult()).intValue();
116
        } else {
117
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());
118

    
119
            if(occurrence != null) {
120
                query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));
121
            }
122

    
123
            if(taxonBase != null) {
124
                query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));
125
            }
126
            query.addProjection(AuditEntity.id().count());
127

    
128
            return ((Long)query.getSingleResult()).intValue();
129
        }
130
    }
131

    
132
    @Override
133
    public int countMedia(SpecimenOrObservationBase occurence) {
134
        checkNotInPriorView("OccurrenceDaoHibernateImpl.countMedia(SpecimenOrObservationBase occurence)");
135
        Query query = getSession().createQuery("select count(media) from SpecimenOrObservationBase occurence join occurence.media media where occurence = :occurence");
136
        query.setParameter("occurence", occurence);
137

    
138
        return ((Long)query.uniqueResult()).intValue();
139
    }
140

    
141
    @Override
142
    public List<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {
143
        checkNotInPriorView("OccurrenceDaoHibernateImpl.getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber)");
144
        Query query = getSession().createQuery("select distinct derivationEvent from DerivationEvent derivationEvent join derivationEvent.originals occurence where occurence = :occurence");
145
        query.setParameter("occurence", occurence);
146

    
147
        if(pageSize != null) {
148
            query.setMaxResults(pageSize);
149
            if(pageNumber != null) {
150
                query.setFirstResult(pageNumber * pageSize);
151
            } else {
152
                query.setFirstResult(0);
153
            }
154
        }
155

    
156
        List<DerivationEvent> result = query.list();
157
        defaultBeanInitializer.initializeAll(result, propertyPaths);
158
        return result;
159
    }
160

    
161
    @Override
162
    public List<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
163
        AuditEvent auditEvent = getAuditEventFromContext();
164
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
165
            Criteria criteria = getSession().createCriteria(DeterminationEvent.class);
166
            if(occurrence != null) {
167
                criteria.add(Restrictions.eq("identifiedUnit",occurrence));
168
            }
169

    
170
            if(taxonBase != null) {
171
                criteria.add(Restrictions.eq("taxon",taxonBase));
172
            }
173

    
174
            if(pageSize != null) {
175
                criteria.setMaxResults(pageSize);
176
                if(pageNumber != null) {
177
                    criteria.setFirstResult(pageNumber * pageSize);
178
                } else {
179
                    criteria.setFirstResult(0);
180
                }
181
            }
182
            List<DeterminationEvent> result = criteria.list();
183
            defaultBeanInitializer.initializeAll(result, propertyPaths);
184
            return result;
185
        } else {
186
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());
187
            if(occurrence != null) {
188
                query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));
189
            }
190

    
191
            if(taxonBase != null) {
192
                query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));
193
            }
194
            if(pageSize != null) {
195
                query.setMaxResults(pageSize);
196
                if(pageNumber != null) {
197
                    query.setFirstResult(pageNumber * pageSize);
198
                } else {
199
                    query.setFirstResult(0);
200
                }
201
            }
202
            List<DeterminationEvent> result = query.getResultList();
203
            defaultBeanInitializer.initializeAll(result, propertyPaths);
204
            return result;
205
        }
206
    }
207

    
208
    @Override
209
    public List<Media> getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
210
        checkNotInPriorView("OccurrenceDaoHibernateImpl.getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths)");
211
        Query query = getSession().createQuery("select media from SpecimenOrObservationBase occurence join occurence.media media where occurence = :occurence");
212
        query.setParameter("occurence", occurence);
213

    
214
        if(pageSize != null) {
215
            query.setMaxResults(pageSize);
216
            if(pageNumber != null) {
217
                query.setFirstResult(pageNumber * pageSize);
218
            } else {
219
                query.setFirstResult(0);
220
            }
221
        }
222

    
223
        List<Media> results = query.list();
224
        defaultBeanInitializer.initializeAll(results, propertyPaths);
225
        return results;
226
    }
227

    
228
    @Override
229
    public void rebuildIndex() {
230
        FullTextSession fullTextSession = Search.getFullTextSession(getSession());
231

    
232
        for(SpecimenOrObservationBase<?> occurrence : list(null,null)) { // re-index all taxon base
233

    
234
            for(DeterminationEvent determination : occurrence.getDeterminations()) {
235
                Hibernate.initialize(determination.getActor());
236
                Hibernate.initialize(determination.getTaxon());
237
            }
238
            Hibernate.initialize(occurrence.getDefinition());
239
            if(occurrence instanceof DerivedUnit) {
240
                DerivedUnit derivedUnit = (DerivedUnit) occurrence;
241
                Hibernate.initialize(derivedUnit.getCollection());
242
                if(derivedUnit.getCollection() != null) {
243
                    Hibernate.initialize(derivedUnit.getCollection().getSuperCollection());
244
                    Hibernate.initialize(derivedUnit.getCollection().getInstitute());
245
                }
246
                Hibernate.initialize(derivedUnit.getStoredUnder());
247
                SpecimenOrObservationBase<?> original = derivedUnit.getOriginalUnit();
248
                if(original != null && original.isInstanceOf(FieldUnit.class)) {
249
                    FieldUnit fieldUnit = CdmBase.deproxy(original, FieldUnit.class);
250
                    Hibernate.initialize(fieldUnit.getGatheringEvent());
251
                    if(fieldUnit.getGatheringEvent() != null) {
252
                        Hibernate.initialize(fieldUnit.getGatheringEvent().getActor());
253
                    }
254
                }
255
            }
256
            fullTextSession.index(occurrence);
257
        }
258
        fullTextSession.flushToIndexes();
259
    }
260

    
261
    @Override
262
    public int count(Class<? extends SpecimenOrObservationBase> clazz,	TaxonName determinedAs) {
263

    
264
        Criteria criteria = null;
265
        if(clazz == null) {
266
            criteria = getSession().createCriteria(type);
267
        } else {
268
            criteria = getSession().createCriteria(clazz);
269
        }
270

    
271
        criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));
272
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
273
        return ((Number)criteria.uniqueResult()).intValue();
274
    }
275

    
276
    @Override
277
    public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonName determinedAs, Integer limit, Integer start,	List<OrderHint> orderHints, List<String> propertyPaths) {
278
        Criteria criteria = null;
279
        if(clazz == null) {
280
            criteria = getSession().createCriteria(type);
281
        } else {
282
            criteria = getSession().createCriteria(clazz);
283
        }
284

    
285
        criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));
286

    
287
        if(limit != null) {
288
            if(start != null) {
289
                criteria.setFirstResult(start);
290
            } else {
291
                criteria.setFirstResult(0);
292
            }
293
            criteria.setMaxResults(limit);
294
        }
295

    
296
        addOrder(criteria,orderHints);
297

    
298
        @SuppressWarnings("unchecked")
299
        List<SpecimenOrObservationBase> results = criteria.list();
300
        defaultBeanInitializer.initializeAll(results, propertyPaths);
301
        return results;
302
    }
303

    
304
    @Override
305
    public int count(Class<? extends SpecimenOrObservationBase> clazz,	TaxonBase determinedAs) {
306

    
307
        Criteria criteria = null;
308
        if(clazz == null) {
309
            criteria = getSession().createCriteria(type);
310
        } else {
311
            criteria = getSession().createCriteria(clazz);
312
        }
313

    
314
        criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));
315
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
316
        return ((Number)criteria.uniqueResult()).intValue();
317
    }
318

    
319
    @Override
320
    public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonBase determinedAs, Integer limit, Integer start,	List<OrderHint> orderHints, List<String> propertyPaths) {
321
        Criteria criteria = null;
322
        if(clazz == null) {
323
            criteria = getSession().createCriteria(type);
324
        } else {
325
            criteria = getSession().createCriteria(clazz);
326
        }
327

    
328
        criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));
329

    
330
        if(limit != null) {
331
            if(start != null) {
332
                criteria.setFirstResult(start);
333
            } else {
334
                criteria.setFirstResult(0);
335
            }
336
            criteria.setMaxResults(limit);
337
        }
338

    
339
        addOrder(criteria,orderHints);
340

    
341
        @SuppressWarnings("unchecked")
342
        List<SpecimenOrObservationBase> results = criteria.list();
343
        defaultBeanInitializer.initializeAll(results, propertyPaths);
344
        return results;
345
    }
346

    
347
    @Override
348
    public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> findOccurrencesUuidAndTitleCache(
349
            Class<T> clazz, String queryString, String significantIdentifier, SpecimenOrObservationType recordBasis,
350
            Taxon associatedTaxon, TaxonName associatedTaxonName, MatchMode matchmode, Integer limit, Integer start,
351
            List<OrderHint> orderHints) {
352
        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
353
                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, null);
354
        if(criteria!=null){
355
            ProjectionList projectionList = Projections.projectionList();
356
            projectionList.add(Projections.property("uuid"));
357
            projectionList.add(Projections.property("id"));
358
            projectionList.add(Projections.property("titleCache"));
359
            criteria.setProjection(projectionList);
360

    
361
            @SuppressWarnings("unchecked")
362
            List<Object[]> result = criteria.list();
363
            List<UuidAndTitleCache<SpecimenOrObservationBase>> uuidAndTitleCacheList = new ArrayList<>();
364
            for(Object[] object : result){
365
                uuidAndTitleCacheList.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));
366
            }
367
            return uuidAndTitleCacheList;
368
        }
369
        return Collections.emptyList();
370
    }
371

    
372
    @Override
373
    public <T extends SpecimenOrObservationBase> List<T> findOccurrences(Class<T> clazz, String queryString,
374
            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,
375
            MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
376

    
377
        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
378
                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);
379
        if(criteria!=null){
380
            @SuppressWarnings("unchecked")
381
            List<T> results = criteria.list();
382
            defaultBeanInitializer.initializeAll(results, propertyPaths);
383
            return results;
384
        }
385
        return Collections.emptyList();
386
    }
387

    
388
    private <T extends SpecimenOrObservationBase> Criteria createFindOccurrenceCriteria(Class<T> clazz, String queryString,
389
            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName, MatchMode matchmode, Integer limit,
390
            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
391
        Criteria criteria = null;
392

    
393
        if(clazz == null) {
394
            criteria = getSession().createCriteria(type);
395
        } else {
396
            criteria = getSession().createCriteria(clazz);
397
        }
398

    
399
        //queryString
400
        if (queryString != null) {
401
            if(matchmode == null) {
402
                matchmode = MatchMode.ANYWHERE;
403
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString)));
404
            } else if(matchmode == MatchMode.BEGINNING) {
405
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.START));
406
            } else if(matchmode == MatchMode.END) {
407
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.END));
408
            } else if(matchmode == MatchMode.EXACT) {
409
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.EXACT));
410
            } else {
411
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.ANYWHERE));
412
            }
413
        }
414

    
415
        //significant identifier
416
        if (significantIdentifier != null) {
417
            criteria.add(Restrictions.or(Restrictions.ilike("accessionNumber", significantIdentifier),
418
                    Restrictions.ilike("catalogNumber", significantIdentifier), Restrictions.ilike("barcode", significantIdentifier)));
419
        }
420

    
421
        //recordBasis/SpecimenOrObservationType
422
        Set<SpecimenOrObservationType> typeAndSubtypes = new HashSet<SpecimenOrObservationType>();
423
        if(recordBasis==null){
424
            //add all types
425
            SpecimenOrObservationType[] values = SpecimenOrObservationType.values();
426
            for (SpecimenOrObservationType specimenOrObservationType : values) {
427
                typeAndSubtypes.add(specimenOrObservationType);
428
            }
429
        }
430
        else{
431
            typeAndSubtypes = recordBasis.getGeneralizationOf(true);
432
            typeAndSubtypes.add(recordBasis);
433
        }
434
        criteria.add(Restrictions.in("recordBasis", typeAndSubtypes));
435

    
436
        Set<UUID> associationUuids = new HashSet<UUID>();
437
        //taxon associations
438
        if(associatedTaxon!=null){
439
            List<UuidAndTitleCache<SpecimenOrObservationBase>> associatedTaxaList = listUuidAndTitleCacheByAssociatedTaxon(clazz, associatedTaxon, limit, start, orderHints);
440
            if(associatedTaxaList!=null){
441
                for (UuidAndTitleCache<SpecimenOrObservationBase> uuidAndTitleCache : associatedTaxaList) {
442
                    associationUuids.add(uuidAndTitleCache.getUuid());
443
                }
444
            }
445
        }
446
        //taxon name associations
447
        else if(associatedTaxonName!=null){
448
            List<? extends SpecimenOrObservationBase> associatedTaxaList = listByAssociatedTaxonName(clazz, associatedTaxonName, limit, start, orderHints, propertyPaths);
449
            if(associatedTaxaList!=null){
450
                for (SpecimenOrObservationBase specimenOrObservationBase : associatedTaxaList) {
451
                    associationUuids.add(specimenOrObservationBase.getUuid());
452
                }
453
            }
454
        }
455
        if(associatedTaxon!=null || associatedTaxonName!=null){
456
            if(!associationUuids.isEmpty()){
457
                criteria.add(Restrictions.in("uuid", associationUuids));
458
            }
459
            else{
460
                return null;
461
            }
462
        }
463
        if(limit != null) {
464
            if(start != null) {
465
                criteria.setFirstResult(start);
466
            } else {
467
                criteria.setFirstResult(0);
468
            }
469
            criteria.setMaxResults(limit);
470
        }
471

    
472
        if(orderHints!=null){
473
            addOrder(criteria,orderHints);
474
        }
475
        return criteria;
476
    }
477

    
478

    
479
    @Override
480
    public <T extends SpecimenOrObservationBase> int countOccurrences(Class<T> clazz, String queryString,
481
            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,
482
            MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
483
        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
484
                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);
485

    
486
        if(criteria!=null){
487

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

    
490
            return ((Number)criteria.uniqueResult()).intValue();
491
        }
492
        return 0;
493
    }
494

    
495
    @Override
496
    public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache(Integer limit, String pattern) {
497
        List<UuidAndTitleCache<DerivedUnit>> list = new ArrayList<>();
498
        Session session = getSession();
499
        Query query;
500
        if (pattern != null){
501
            query = session.createQuery("select uuid, id, titleCache from " + type.getSimpleName() + " where NOT dtype = " + FieldUnit.class.getSimpleName() +" AND titleCache like :pattern");
502
            pattern = pattern.replace("*", "%");
503
            pattern = pattern.replace("?", "_");
504
            pattern = pattern + "%";
505
            query.setParameter("pattern", pattern);
506
        } else {
507
            query = session.createQuery("select uuid, id, titleCache from " + type.getSimpleName() +" where NOT dtype = " + FieldUnit.class.getSimpleName());
508
        }
509
        if (limit != null){
510
           query.setMaxResults(limit);
511
        }
512

    
513
        @SuppressWarnings("unchecked")
514
        List<Object[]> result = query.list();
515

    
516
        for(Object[] object : result){
517
            list.add(new UuidAndTitleCache<DerivedUnit>(DerivedUnit.class, (UUID) object[0], (Integer)object[1], (String) object[2]));
518
        }
519

    
520
        return list;
521
    }
522

    
523
    @Override
524
    public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
525
        List<UuidAndTitleCache<FieldUnit>> list = new ArrayList<UuidAndTitleCache<FieldUnit>>();
526
        Session session = getSession();
527

    
528
        Query query = session.createQuery("select uuid, id, titleCache from " + type.getSimpleName() + " where dtype = " + FieldUnit.class.getSimpleName());
529

    
530
        @SuppressWarnings("unchecked")
531
        List<Object[]> result = query.list();
532

    
533
        for(Object[] object : result){
534
            list.add(new UuidAndTitleCache<FieldUnit>(FieldUnit.class, (UUID) object[0], (Integer)object[1], (String) object[2]));
535
        }
536

    
537
        return list;
538
    }
539

    
540
    @Override
541
    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxonName(Class<T> type,
542
            TaxonName associatedTaxonName, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
543
        Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();
544

    
545
        // A Taxon name may be referenced by the DeterminationEvent of the SpecimenOrObservationBase
546
        List<SpecimenOrObservationBase> byDetermination = list(type, associatedTaxonName, null, 0, null, null);
547
        setOfAll.addAll(byDetermination);
548

    
549
        if(setOfAll.size() == 0){
550
            // no need querying the data base
551
            return new ArrayList<T>();
552
        }
553

    
554
        String queryString =
555
            "select sob " +
556
            " from SpecimenOrObservationBase sob" +
557
            " where sob in (:setOfAll)";
558

    
559
        if(type != null && !type.equals(SpecimenOrObservationBase.class)){
560
            queryString += " and sob.class = :type";
561
        }
562

    
563
        if(orderHints != null && orderHints.size() > 0){
564
            queryString += " order by ";
565
            String orderStr = "";
566
            for(OrderHint orderHint : orderHints){
567
                if(orderStr.length() > 0){
568
                    orderStr += ", ";
569
                }
570
                queryString += "sob." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
571
            }
572
            queryString += orderStr;
573
        }
574

    
575
        Query query = getSession().createQuery(queryString);
576
        query.setParameterList("setOfAll", setOfAll);
577

    
578
        if(type != null && !type.equals(SpecimenOrObservationBase.class)){
579
            query.setParameter("type", type.getSimpleName());
580
        }
581

    
582
        if(limit != null) {
583
            if(start != null) {
584
                query.setFirstResult(start);
585
            } else {
586
                query.setFirstResult(0);
587
            }
588
            query.setMaxResults(limit);
589
        }
590

    
591

    
592
        @SuppressWarnings("unchecked")
593
        List<T> results = query.list();
594
        defaultBeanInitializer.initializeAll(results, propertyPaths);
595
        return results;
596
    }
597

    
598
    private List<SpecimenNodeWrapper> querySpecimen(
599
            Query query, List<UUID> taxonNodeUuids,
600
            Integer limit, Integer start){
601
        query.setParameterList("taxonNodeUuids", taxonNodeUuids);
602

    
603
        if(limit != null) {
604
            if(start != null) {
605
                query.setFirstResult(start);
606
            } else {
607
                query.setFirstResult(0);
608
            }
609
            query.setMaxResults(limit);
610
        }
611

    
612
        List<SpecimenNodeWrapper> list = new ArrayList<>();
613
        @SuppressWarnings("unchecked")
614
        List<Object[]> result = query.list();
615
        for(Object[] object : result){
616
            list.add(new SpecimenNodeWrapper(
617
                    new UuidAndTitleCache<>(
618
                            (UUID) object[0],
619
                            (Integer) object[1],
620
                            (String) object[2]),
621
                    (TaxonNode)object[3]));
622
        }
623
        return list;
624
    }
625

    
626
    private List<SpecimenNodeWrapper> queryIndividualAssociatedSpecimen(List<UUID> taxonNodeUuids,
627
            Integer limit, Integer start){
628
        String queryString =  "SELECT "
629
                + "de.associatedSpecimenOrObservation.uuid, "
630
                + "de.associatedSpecimenOrObservation.id, "
631
                + "de.associatedSpecimenOrObservation.titleCache, "
632
                + "tn "
633
                + "FROM DescriptionElementBase AS de "
634
                + "LEFT JOIN de.inDescription AS d "
635
                + "LEFT JOIN d.taxon AS t "
636
                + "JOIN t.taxonNodes AS tn "
637
                + "WHERE d.class = 'TaxonDescription' "
638
                + "AND tn.uuid in (:taxonNodeUuids) "
639
                ;
640
        Query query = getSession().createQuery(queryString);
641
        return querySpecimen(query, taxonNodeUuids, limit, start);
642
    }
643

    
644
    private List<SpecimenNodeWrapper> queryTypeSpecimen(List<UUID> taxonNodeUuids,
645
            Integer limit, Integer start){
646
        String queryString =  "SELECT "
647
                + "td.typeSpecimen.uuid, "
648
                + "td.typeSpecimen.id, "
649
                + "td.typeSpecimen.titleCache, "
650
                + "tn "
651
                + "FROM SpecimenTypeDesignation AS td "
652
                + "LEFT JOIN td.typifiedNames AS tn "
653
                + "LEFT JOIN tn.taxonBases AS t "
654
                + "JOIN t.taxonNodes AS tn "
655
                + "WHERE tn.uuid in (:taxonNodeUuids) "
656
                ;
657
        Query query = getSession().createQuery(queryString);
658
        return querySpecimen(query, taxonNodeUuids, limit, start);
659
    }
660

    
661
    private List<SpecimenNodeWrapper> queryTaxonDeterminations(List<UUID> taxonNodeUuids,
662
            Integer limit, Integer start){
663
        String queryString =  "SELECT "
664
                + "det.identifiedUnit.uuid, "
665
                + "det.identifiedUnit.id, "
666
                + "det.identifiedUnit.titleCache, "
667
                + "tn "
668
                + "FROM DeterminationEvent AS det "
669
                + "LEFT JOIN det.taxon AS t "
670
                + "JOIN t.taxonNodes AS tn "
671
                + "WHERE tn.uuid in (:taxonNodeUuids) "
672
                ;
673
        Query query = getSession().createQuery(queryString);
674
        return querySpecimen(query, taxonNodeUuids, limit, start);
675
    }
676

    
677
    private List<SpecimenNodeWrapper> queryTaxonNameDeterminations(List<UUID> taxonNodeUuids,
678
            Integer limit, Integer start){
679
        String queryString =  "SELECT "
680
                + "det.identifiedUnit.uuid, "
681
                + "det.identifiedUnit.id, "
682
                + "det.identifiedUnit.titleCache, "
683
                + "tn "
684
                + "FROM DeterminationEvent AS det "
685
                + "LEFT JOIN det.taxonName AS n "
686
                + "LEFT JOIN n.taxonBases AS t "
687
                + "JOIN t.taxonNodes AS tn "
688
                + "WHERE tn.uuid in (:taxonNodeUuids) "
689
                ;
690
        Query query = getSession().createQuery(queryString);
691
        return querySpecimen(query, taxonNodeUuids, limit, start);
692
    }
693

    
694
    @Override
695
    public Collection<SpecimenNodeWrapper> listUuidAndTitleCacheByAssociatedTaxon(List<UUID> taxonNodeUuids,
696
            Integer limit, Integer start){
697

    
698
        Collection<SpecimenNodeWrapper> wrappers = new HashSet<>();
699
        wrappers.addAll(queryIndividualAssociatedSpecimen(taxonNodeUuids, limit, start));
700
        wrappers.addAll(queryTaxonDeterminations(taxonNodeUuids, limit, start));
701
        wrappers.addAll(queryTaxonNameDeterminations(taxonNodeUuids, limit, start));
702
        wrappers.addAll(queryTypeSpecimen(taxonNodeUuids, limit, start));
703

    
704
        return wrappers;
705
    }
706

    
707
    @Override
708
    public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> listUuidAndTitleCacheByAssociatedTaxon(Class<T> clazz, Taxon associatedTaxon,
709
            Integer limit, Integer start, List<OrderHint> orderHints){
710
        Query query = createSpecimenQuery("sob.uuid, sob.id, sob.titleCache", clazz, associatedTaxon, limit, start, orderHints, null);
711
        if(query==null){
712
            return Collections.emptyList();
713
        }
714
        List<UuidAndTitleCache<SpecimenOrObservationBase>> list = new ArrayList<>();
715
        @SuppressWarnings("unchecked")
716
        List<Object[]> result = query.list();
717
        for(Object[] object : result){
718
            list.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));
719
        }
720
        return list;
721
    }
722

    
723
    @Override
724
    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> clazz,
725
            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
726
        Query query = createSpecimenQuery("sob", clazz, associatedTaxon, limit, start, orderHints, propertyPaths);
727
        if(query==null){
728
            return Collections.emptyList();
729
        }
730
        @SuppressWarnings("unchecked")
731
        List<T> results = query.list();
732
        defaultBeanInitializer.initializeAll(results, propertyPaths);
733
        return results;
734
    }
735

    
736
    private <T extends SpecimenOrObservationBase> Query createSpecimenQuery(String select, Class<T> clazz,
737
            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths){
738
        Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();
739
        Set<Integer> setOfAllIds = new HashSet<>();
740

    
741
        Criteria criteria = null;
742
        if(clazz == null) {
743
            criteria = getSession().createCriteria(type, "specimen");
744
        } else {
745
            criteria = getSession().createCriteria(clazz, "specimen");
746
        }
747

    
748
        Disjunction determinationOr = Restrictions.disjunction();
749

    
750
        // A Taxon may be referenced by the DeterminationEvent of the SpecimenOrObservationBase
751
        Criteria determinationsCriteria = criteria.createCriteria("determinations");
752

    
753
        determinationOr.add(Restrictions.eq("taxon", associatedTaxon));
754
        //check also for synonyms
755
        for (Synonym synonym : associatedTaxon.getSynonyms()) {
756
            determinationOr.add(Restrictions.eq("taxon", synonym));
757
        }
758

    
759
        //check also for name determinations
760
        determinationOr.add(Restrictions.eq("taxonName", associatedTaxon.getName()));
761
        for (TaxonName synonymName : associatedTaxon.getSynonymNames()) {
762
            determinationOr.add(Restrictions.eq("taxonName", synonymName));
763
        }
764

    
765
        determinationsCriteria.add(determinationOr);
766

    
767
        if(limit != null) {
768
            if(start != null) {
769
                criteria.setFirstResult(start);
770
            } else {
771
                criteria.setFirstResult(0);
772
            }
773
            criteria.setMaxResults(limit);
774
        }
775
        criteria.setProjection(Projections.property("id"));
776

    
777
        addOrder(criteria,orderHints);
778

    
779
        @SuppressWarnings("unchecked")
780
        List<Integer> detResults = criteria.list();
781
        setOfAllIds.addAll(detResults);
782

    
783
        // The IndividualsAssociation elements in a TaxonDescription contain DerivedUnits
784
        setOfAllIds.addAll(descriptionDao.getIndividualAssociationSpecimenIDs(
785
                associatedTaxon.getUuid(), null, null, 0, null));
786

    
787

    
788
        // SpecimenTypeDesignations may be associated with the TaxonName.
789
        setOfAllIds.addAll(taxonNameDao.getTypeSpecimenIdsForTaxonName(
790
                associatedTaxon.getName(), null, null, null));
791

    
792
        // SpecimenTypeDesignations may be associated with any HomotypicalGroup related to the specific Taxon.
793
        //TODO adapt to set of ids
794
        for(HomotypicalGroup homotypicalGroup :  associatedTaxon.getHomotypicSynonymyGroups()) {
795
            List<SpecimenTypeDesignation> byHomotypicalGroup = homotypicalGroupDao.getTypeDesignations(homotypicalGroup, SpecimenTypeDesignation.class, null, null, 0, null);
796
            for (SpecimenTypeDesignation specimenTypeDesignation : byHomotypicalGroup) {
797
                setOfAll.add(specimenTypeDesignation.getTypeSpecimen());
798
            }
799
        }
800

    
801
        if(setOfAllIds.size() == 0){
802
            // no need querying the data base
803
            return null;
804
        }
805

    
806
        String queryString =
807
            "select "+select+
808
            " from SpecimenOrObservationBase sob" +
809
            " where sob.id in (:setOfAllIds)";
810

    
811
        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
812
            queryString += " and sob.class = :type ";
813
        }
814

    
815
        if(orderHints != null && orderHints.size() > 0){
816
            queryString += " order by ";
817
            String orderStr = "";
818
            for(OrderHint orderHint : orderHints){
819
                if(orderStr.length() > 0){
820
                    orderStr += ", ";
821
                }
822
                queryString += "sob." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
823
            }
824
            queryString += orderStr;
825
        }
826

    
827
        Query query = getSession().createQuery(queryString);
828
        query.setParameterList("setOfAllIds", setOfAllIds);
829

    
830
        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
831
            query.setParameter("type", clazz.getSimpleName());
832
        }
833

    
834
        if(limit != null) {
835
            if(start != null) {
836
                query.setFirstResult(start);
837
            } else {
838
                query.setFirstResult(0);
839
            }
840
            query.setMaxResults(limit);
841
        }
842

    
843
        return query;
844
    }
845

    
846
    @Override
847
    public Collection<SpecimenOrObservationBase> listBySpecimenOrObservationType(SpecimenOrObservationType type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
848
        String queryString = "FROM SpecimenOrObservationBase specimens "
849
                + " WHERE specimens.recordBasis = :type ";
850

    
851
        queryString += orderByClause(orderHints, "specimens");
852

    
853
        Query query = getSession().createQuery(queryString);
854
        query.setParameter("type", type);
855

    
856
        if(limit != null) {
857
            if(start != null) {
858
                query.setFirstResult(start);
859
            } else {
860
                query.setFirstResult(0);
861
            }
862
            query.setMaxResults(limit);
863
        }
864

    
865
        @SuppressWarnings({ "unchecked", "rawtypes" })
866
        List<SpecimenOrObservationBase> results = query.list();
867
        defaultBeanInitializer.initializeAll(results, propertyPaths);
868
        return results;
869
    }
870

    
871

    
872
    @Override
873
    public Collection<DeterminationEvent> listDeterminationEvents(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
874
        String queryString = "FROM DeterminationEvent determination "
875
                + " WHERE determination.identifiedUnit = :specimen";
876

    
877
        queryString += orderByClause(orderHints, "determination");
878

    
879
        Query query = getSession().createQuery(queryString);
880
        query.setParameter("specimen", specimen);
881

    
882
        if(limit != null) {
883
            if(start != null) {
884
                query.setFirstResult(start);
885
            } else {
886
                query.setFirstResult(0);
887
            }
888
            query.setMaxResults(limit);
889
        }
890

    
891
        @SuppressWarnings("unchecked")
892
        List<DeterminationEvent> results = query.list();
893
        defaultBeanInitializer.initializeAll(results, propertyPaths);
894
        return results;
895
    }
896

    
897
    @Override
898
    public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
899
        String queryString = "FROM SpecimenTypeDesignation designations "
900
                + " WHERE designations.typeSpecimen = :specimen";
901

    
902
        queryString += orderByClause(orderHints, "designations");
903

    
904
        Query query = getSession().createQuery(queryString);
905
        query.setParameter("specimen", specimen);
906

    
907
        if(limit != null) {
908
            if(start != null) {
909
                query.setFirstResult(start);
910
            } else {
911
                query.setFirstResult(0);
912
            }
913
            query.setMaxResults(limit);
914
        }
915

    
916
        @SuppressWarnings("unchecked")
917
        List<SpecimenTypeDesignation> results = query.list();
918
        defaultBeanInitializer.initializeAll(results, propertyPaths);
919
        return results;
920
    }
921

    
922
    @Override
923
    public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
924
        //DISTINCT is necessary if more than one description exists for a taxon because we create the cross product of all taxon descriptions and description elements
925
        String queryString = "FROM IndividualsAssociation associations WHERE associations.associatedSpecimenOrObservation = :specimen";
926

    
927
        queryString += orderByClause(orderHints, "associations");
928

    
929
        Query query = getSession().createQuery(queryString);
930
        query.setParameter("specimen", specimen);
931

    
932
        if(limit != null) {
933
            if(start != null) {
934
                query.setFirstResult(start);
935
            } else {
936
                query.setFirstResult(0);
937
            }
938
            query.setMaxResults(limit);
939
        }
940

    
941
        @SuppressWarnings("unchecked")
942
        List<IndividualsAssociation> results = query.list();
943
        defaultBeanInitializer.initializeAll(results, propertyPaths);
944
        return results;
945
    }
946

    
947
    @Override
948
    public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
949
        //DISTINCT is necessary if more than one description exists for a taxon because we create the cross product of all taxon descriptions and description elements
950
        String queryString = "FROM DescriptionBase descriptions "
951
                + " WHERE descriptions.describedSpecimenOrObservation = :specimen";
952

    
953
        queryString += orderByClause(orderHints, "descriptions");
954

    
955
        Query query = getSession().createQuery(queryString);
956
        query.setParameter("specimen", specimen);
957

    
958
        if(limit != null) {
959
            if(start != null) {
960
                query.setFirstResult(start);
961
            } else {
962
                query.setFirstResult(0);
963
            }
964
            query.setMaxResults(limit);
965
        }
966

    
967
        @SuppressWarnings("unchecked")
968
        List<DescriptionBase<?>> results = query.list();
969
        defaultBeanInitializer.initializeAll(results, propertyPaths);
970
        return results;
971
    }
972

    
973
    /**
974
     * {@inheritDoc}
975
     */
976
    @Override
977
    public List<FieldUnit> getFieldUnitsForGatheringEvent(UUID gatheringEventUuid, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
978
        String queryString = "FROM SpecimenOrObservationBase sob "
979
                + "WHERE sob.gatheringEvent.uuid = :gatheringEventUuid";
980

    
981
        queryString += orderByClause(orderHints, "sob");
982

    
983
        Query query = getSession().createQuery(queryString);
984
        query.setParameter("gatheringEventUuid", gatheringEventUuid);
985

    
986
        if(limit != null) {
987
            if(start != null) {
988
                query.setFirstResult(start);
989
            } else {
990
                query.setFirstResult(0);
991
            }
992
            query.setMaxResults(limit);
993
        }
994

    
995
        @SuppressWarnings("unchecked")
996
        List<FieldUnit> results = query.list();
997
        defaultBeanInitializer.initializeAll(results, propertyPaths);
998
        return results;
999
    }
1000

    
1001
    /**
1002
     * {@inheritDoc}
1003
     */
1004
    @Override
1005
    public List<DerivedUnit> getByGeneticAccessionNumber(String accessionNumberString, List<String> propertyPaths) {
1006
        String queryString = "SELECT dnaSample FROM DnaSample dnaSample join dnaSample.sequences sequence WHERE sequence.geneticAccessionNumber LIKE :accessionNumberString";
1007
        Query query = getSession().createQuery(queryString);
1008
        query.setParameter("accessionNumberString", accessionNumberString);
1009
        @SuppressWarnings("unchecked")
1010
        List<DerivedUnit> results = query.list();
1011
        defaultBeanInitializer.initializeAll(results, propertyPaths);
1012
        return results;
1013
    }
1014

    
1015
}
(2-2/2)