Project

General

Profile

Download (46.3 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
 * @created 01.09.2008
66
 */
67
@Repository
68
public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrObservationBase> implements IOccurrenceDao {
69

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

    
73
    @Autowired
74
    private IDescriptionDao descriptionDao;
75

    
76
    @Autowired
77
    private ITaxonNameDao taxonNameDao;
78

    
79
    @Autowired
80
    private IHomotypicalGroupDao homotypicalGroupDao;
81

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

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

    
96
        return ((Long)query.uniqueResult()).intValue();
97
    }
98

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

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

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

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

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

    
126
            return ((Long)query.getSingleResult()).intValue();
127
        }
128
    }
129

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

    
136
        return ((Long)query.uniqueResult()).intValue();
137
    }
138

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
283
        criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));
284

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

    
294
        addOrder(criteria,orderHints);
295

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

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

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

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

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

    
326
        criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));
327

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

    
337
        addOrder(criteria,orderHints);
338

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

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

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

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

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

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

    
390
        if(clazz == null) {
391
            criteria = getSession().createCriteria(type);
392
        } else {
393
            criteria = getSession().createCriteria(clazz);
394
        }
395

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

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

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

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

    
469
        if(orderHints!=null){
470
            addOrder(criteria,orderHints);
471
        }
472
        return criteria;
473
    }
474

    
475

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

    
483
        if(criteria!=null){
484

    
485
            criteria.setProjection(Projections.rowCount());
486

    
487
            return ((Number)criteria.uniqueResult()).intValue();
488
        }
489
        return 0;
490
    }
491

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

    
510

    
511

    
512
        List<Object[]> result = query.list();
513

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

    
518
        return list;
519
    }
520

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

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

    
528
        List<Object[]> result = query.list();
529

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

    
534
        return list;
535
    }
536

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

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

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

    
551
        String queryString =
552
            "select sob " +
553
            " from SpecimenOrObservationBase sob" +
554
            " where sob in (:setOfAll)";
555

    
556
        if(type != null && !type.equals(SpecimenOrObservationBase.class)){
557
            queryString += " and sob.class = :type";
558
        }
559

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

    
572
        Query query = getSession().createQuery(queryString);
573
        query.setParameterList("setOfAll", setOfAll);
574

    
575
        if(type != null && !type.equals(SpecimenOrObservationBase.class)){
576
            query.setParameter("type", type.getSimpleName());
577
        }
578

    
579
        if(limit != null) {
580
            if(start != null) {
581
                query.setFirstResult(start);
582
            } else {
583
                query.setFirstResult(0);
584
            }
585
            query.setMaxResults(limit);
586
        }
587

    
588

    
589
        List<T> results = query.list();
590
        defaultBeanInitializer.initializeAll(results, propertyPaths);
591
        return results;
592
    }
593

    
594
    private List<SpecimenNodeWrapper> queryIndividualAssociatedSpecimen(List<UUID> taxonNodeUuids,
595
            Integer limit, Integer start, List<OrderHint> orderHintss){
596
        String queryString =  "SELECT "
597
                + "de.associatedSpecimenOrObservation.uuid, "
598
                + "de.associatedSpecimenOrObservation.id, "
599
                + "de.associatedSpecimenOrObservation.titleCache, "
600
                + "tn "
601
                + "FROM DescriptionElementBase AS de "
602
                + "LEFT JOIN de.inDescription AS d "
603
                + "LEFT JOIN d.taxon AS t "
604
                + "JOIN t.taxonNodes AS tn "
605
                + "WHERE d.class = 'TaxonDescription' "
606
                + "AND tn.uuid in (:taxonNodeUuids) "
607
                ;
608
        Query query = getSession().createQuery(queryString);
609

    
610
        query.setParameterList("taxonNodeUuids", taxonNodeUuids);
611

    
612
        if(limit != null) {
613
            if(start != null) {
614
                query.setFirstResult(start);
615
            } else {
616
                query.setFirstResult(0);
617
            }
618
            query.setMaxResults(limit);
619
        }
620

    
621
        List<SpecimenNodeWrapper> list = new ArrayList<>();
622
        List<Object[]> result = query.list();
623
        for(Object[] object : result){
624
            list.add(new SpecimenNodeWrapper(
625
                    new UuidAndTitleCache<SpecimenOrObservationBase>(
626
                            (UUID) object[0],
627
                            (Integer) object[1],
628
                            (String) object[2]),
629
                    (TaxonNode)object[3]));
630
        }
631
        return list;
632
    }
633

    
634
    private List<SpecimenNodeWrapper> queryTypeSpecimen(List<UUID> taxonNodeUuids,
635
            Integer limit, Integer start, List<OrderHint> orderHints){
636
        String queryString =  "SELECT "
637
                + "td.typeSpecimen.uuid, "
638
                + "td.typeSpecimen.id, "
639
                + "td.typeSpecimen.titleCache, "
640
                + "tn "
641
                + "FROM SpecimenTypeDesignation AS td "
642
                + "LEFT JOIN td.typifiedNames AS tn "
643
                + "LEFT JOIN tn.taxonBases AS t "
644
                + "JOIN t.taxonNodes AS tn "
645
                + "WHERE tn.uuid in (:taxonNodeUuids) "
646
                ;
647
        Query query = getSession().createQuery(queryString);
648

    
649
        query.setParameterList("taxonNodeUuids", taxonNodeUuids);
650

    
651
        if(limit != null) {
652
            if(start != null) {
653
                query.setFirstResult(start);
654
            } else {
655
                query.setFirstResult(0);
656
            }
657
            query.setMaxResults(limit);
658
        }
659

    
660
        List<SpecimenNodeWrapper> list = new ArrayList<>();
661
        List<Object[]> result = query.list();
662
        for(Object[] object : result){
663
            list.add(new SpecimenNodeWrapper(
664
                    new UuidAndTitleCache<SpecimenOrObservationBase>(
665
                            (UUID) object[0],
666
                            (Integer) object[1],
667
                            (String) object[2]),
668
                    (TaxonNode)object[3]));
669
        }
670
        return list;
671
    }
672

    
673
    private List<SpecimenNodeWrapper> queryTaxonDeterminations(List<UUID> taxonNodeUuids,
674
            Integer limit, Integer start, List<OrderHint> orderHints){
675
        String queryString =  "SELECT "
676
                + "det.identifiedUnit.uuid, "
677
                + "det.identifiedUnit.id, "
678
                + "det.identifiedUnit.titleCache, "
679
                + "tn "
680
                + "FROM DeterminationEvent AS det "
681
                + "LEFT JOIN det.taxon AS t "
682
                + "JOIN t.taxonNodes AS tn "
683
                + "WHERE tn.uuid in (:taxonNodeUuids) "
684
                ;
685
        Query query = getSession().createQuery(queryString);
686

    
687
        query.setParameterList("taxonNodeUuids", taxonNodeUuids);
688

    
689
        if(limit != null) {
690
            if(start != null) {
691
                query.setFirstResult(start);
692
            } else {
693
                query.setFirstResult(0);
694
            }
695
            query.setMaxResults(limit);
696
        }
697

    
698
        List<SpecimenNodeWrapper> list = new ArrayList<>();
699
        List<Object[]> result = query.list();
700
        for(Object[] object : result){
701
            list.add(new SpecimenNodeWrapper(
702
                    new UuidAndTitleCache<SpecimenOrObservationBase>(
703
                            (UUID) object[0],
704
                            (Integer) object[1],
705
                            (String) object[2]),
706
                    (TaxonNode)object[3]));
707
        }
708
        return list;
709
    }
710

    
711
    private List<SpecimenNodeWrapper> queryTaxonNameDeterminations(List<UUID> taxonNodeUuids,
712
            Integer limit, Integer start, List<OrderHint> orderHints){
713
        String queryString =  "SELECT "
714
                + "det.identifiedUnit.uuid, "
715
                + "det.identifiedUnit.id, "
716
                + "det.identifiedUnit.titleCache, "
717
                + "tn "
718
                + "FROM DeterminationEvent AS det "
719
                + "LEFT JOIN det.taxonName AS n "
720
                + "LEFT JOIN n.taxonBases AS t "
721
                + "JOIN t.taxonNodes AS tn "
722
                + "WHERE tn.uuid in (:taxonNodeUuids) "
723
                ;
724
        Query query = getSession().createQuery(queryString);
725

    
726
        query.setParameterList("taxonNodeUuids", taxonNodeUuids);
727

    
728
        if(limit != null) {
729
            if(start != null) {
730
                query.setFirstResult(start);
731
            } else {
732
                query.setFirstResult(0);
733
            }
734
            query.setMaxResults(limit);
735
        }
736

    
737
        List<SpecimenNodeWrapper> list = new ArrayList<>();
738
        List<Object[]> result = query.list();
739
        for(Object[] object : result){
740
            list.add(new SpecimenNodeWrapper(
741
                    new UuidAndTitleCache<SpecimenOrObservationBase>(
742
                            (UUID) object[0],
743
                            (Integer) object[1],
744
                            (String) object[2]),
745
                    (TaxonNode)object[3]));
746
        }
747
        return list;
748
    }
749

    
750
    @Override
751
    public Collection<SpecimenNodeWrapper> listUuidAndTitleCacheByAssociatedTaxon(List<UUID> taxonNodeUuids,
752
            Integer limit, Integer start, List<OrderHint> orderHints){
753

    
754
        Collection<SpecimenNodeWrapper> wrappers = new HashSet<>();
755
        wrappers.addAll(queryIndividualAssociatedSpecimen(taxonNodeUuids, limit, start, orderHints));
756
        wrappers.addAll(queryTaxonDeterminations(taxonNodeUuids, limit, start, orderHints));
757
        wrappers.addAll(queryTaxonNameDeterminations(taxonNodeUuids, limit, start, orderHints));
758
        wrappers.addAll(queryTypeSpecimen(taxonNodeUuids, limit, start, orderHints));
759

    
760
        return wrappers;
761
    }
762

    
763
    @Override
764
    public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> listUuidAndTitleCacheByAssociatedTaxon(Class<T> clazz, Taxon associatedTaxon,
765
            Integer limit, Integer start, List<OrderHint> orderHints){
766
        Query query = createSpecimenQuery("sob.uuid, sob.id, sob.titleCache", clazz, associatedTaxon, limit, start, orderHints, null);
767
        if(query==null){
768
            return Collections.emptyList();
769
        }
770
        List<UuidAndTitleCache<SpecimenOrObservationBase>> list = new ArrayList<>();
771
        List<Object[]> result = query.list();
772
        for(Object[] object : result){
773
            list.add(new UuidAndTitleCache<SpecimenOrObservationBase>((UUID) object[0],(Integer) object[1], (String) object[2]));
774
        }
775
        return list;
776
    }
777

    
778
    @Override
779
    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> clazz,
780
            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
781
        Query query = createSpecimenQuery("sob", clazz, associatedTaxon, limit, start, orderHints, propertyPaths);
782
        if(query==null){
783
            return Collections.emptyList();
784
        }
785
        List<T> results = query.list();
786
        defaultBeanInitializer.initializeAll(results, propertyPaths);
787
        return results;
788
    }
789

    
790
    private <T extends SpecimenOrObservationBase> Query createSpecimenQuery(String select, Class<T> clazz,
791
            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths){
792
        Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();
793
        Set<Integer> setOfAllIds = new HashSet<>();
794

    
795
        Criteria criteria = null;
796
        if(clazz == null) {
797
            criteria = getSession().createCriteria(type, "specimen");
798
        } else {
799
            criteria = getSession().createCriteria(clazz, "specimen");
800
        }
801

    
802
        Disjunction determinationOr = Restrictions.disjunction();
803

    
804
        // A Taxon may be referenced by the DeterminationEvent of the SpecimenOrObservationBase
805
        Criteria determinationsCriteria = criteria.createCriteria("determinations");
806

    
807
        determinationOr.add(Restrictions.eq("taxon", associatedTaxon));
808
        //check also for synonyms
809
        for (Synonym synonym : associatedTaxon.getSynonyms()) {
810
            determinationOr.add(Restrictions.eq("taxon", synonym));
811
        }
812

    
813
        //check also for name determinations
814
        determinationOr.add(Restrictions.eq("taxonName", associatedTaxon.getName()));
815
        for (TaxonName synonymName : associatedTaxon.getSynonymNames()) {
816
            determinationOr.add(Restrictions.eq("taxonName", synonymName));
817
        }
818

    
819
        determinationsCriteria.add(determinationOr);
820

    
821
        if(limit != null) {
822
            if(start != null) {
823
                criteria.setFirstResult(start);
824
            } else {
825
                criteria.setFirstResult(0);
826
            }
827
            criteria.setMaxResults(limit);
828
        }
829
        criteria.setProjection(Projections.property("id"));
830

    
831
        addOrder(criteria,orderHints);
832

    
833
        @SuppressWarnings("unchecked")
834
        List<Integer> detResults = criteria.list();
835
        setOfAllIds.addAll(detResults);
836

    
837
        // The IndividualsAssociation elements in a TaxonDescription contain DerivedUnits
838
        setOfAllIds.addAll(descriptionDao.getIndividualAssociationSpecimenIDs(
839
                associatedTaxon.getUuid(), null, null, 0, null));
840

    
841

    
842
        // SpecimenTypeDesignations may be associated with the TaxonName.
843
        setOfAllIds.addAll(taxonNameDao.getTypeSpecimenIdsForTaxonName(
844
                associatedTaxon.getName(), null, null, null));
845

    
846
        // SpecimenTypeDesignations may be associated with any HomotypicalGroup related to the specific Taxon.
847
        //TODO adapt to set of ids
848
        for(HomotypicalGroup homotypicalGroup :  associatedTaxon.getHomotypicSynonymyGroups()) {
849
            List<SpecimenTypeDesignation> byHomotypicalGroup = homotypicalGroupDao.getTypeDesignations(homotypicalGroup, SpecimenTypeDesignation.class, null, null, 0, null);
850
            for (SpecimenTypeDesignation specimenTypeDesignation : byHomotypicalGroup) {
851
                setOfAll.add(specimenTypeDesignation.getTypeSpecimen());
852
            }
853
        }
854

    
855
        if(setOfAllIds.size() == 0){
856
            // no need querying the data base
857
            return null;
858
        }
859

    
860
        String queryString =
861
            "select "+select+
862
            " from SpecimenOrObservationBase sob" +
863
            " where sob.id in (:setOfAllIds)";
864

    
865
        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
866
            queryString += " and sob.class = :type ";
867
        }
868

    
869
        if(orderHints != null && orderHints.size() > 0){
870
            queryString += " order by ";
871
            String orderStr = "";
872
            for(OrderHint orderHint : orderHints){
873
                if(orderStr.length() > 0){
874
                    orderStr += ", ";
875
                }
876
                queryString += "sob." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
877
            }
878
            queryString += orderStr;
879
        }
880

    
881
        Query query = getSession().createQuery(queryString);
882
        query.setParameterList("setOfAllIds", setOfAllIds);
883

    
884
        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
885
            query.setParameter("type", clazz.getSimpleName());
886
        }
887

    
888
        if(limit != null) {
889
            if(start != null) {
890
                query.setFirstResult(start);
891
            } else {
892
                query.setFirstResult(0);
893
            }
894
            query.setMaxResults(limit);
895
        }
896

    
897
        return query;
898
    }
899

    
900
    @Override
901
    public Collection<SpecimenOrObservationBase> listBySpecimenOrObservationType(SpecimenOrObservationType type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
902
        String queryString = "FROM SpecimenOrObservationBase specimens WHERE specimens.recordBasis = :type";
903

    
904
        if(orderHints != null && orderHints.size() > 0){
905
            queryString += " order by ";
906
            String orderStr = "";
907
            for(OrderHint orderHint : orderHints){
908
                if(orderStr.length() > 0){
909
                    orderStr += ", ";
910
                }
911
                queryString += "specimens." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
912
            }
913
            queryString += orderStr;
914
        }
915

    
916
        Query query = getSession().createQuery(queryString);
917
        query.setParameter("type", type);
918

    
919
        if(limit != null) {
920
            if(start != null) {
921
                query.setFirstResult(start);
922
            } else {
923
                query.setFirstResult(0);
924
            }
925
            query.setMaxResults(limit);
926
        }
927

    
928
        List results = query.list();
929
        defaultBeanInitializer.initializeAll(results, propertyPaths);
930
        return results;
931
    }
932

    
933
    @Override
934
    public Collection<DeterminationEvent> listDeterminationEvents(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
935
        String queryString = "FROM DeterminationEvent determination WHERE determination.identifiedUnit = :specimen";
936

    
937
        if(orderHints != null && orderHints.size() > 0){
938
            queryString += " order by ";
939
            String orderStr = "";
940
            for(OrderHint orderHint : orderHints){
941
                if(orderStr.length() > 0){
942
                    orderStr += ", ";
943
                }
944
                queryString += "determination." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
945
            }
946
            queryString += orderStr;
947
        }
948

    
949
        Query query = getSession().createQuery(queryString);
950
        query.setParameter("specimen", specimen);
951

    
952
        if(limit != null) {
953
            if(start != null) {
954
                query.setFirstResult(start);
955
            } else {
956
                query.setFirstResult(0);
957
            }
958
            query.setMaxResults(limit);
959
        }
960

    
961
        List results = query.list();
962
        defaultBeanInitializer.initializeAll(results, propertyPaths);
963
        return results;
964
    }
965

    
966
    @Override
967
    public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
968
        String queryString = "FROM SpecimenTypeDesignation designations WHERE designations.typeSpecimen = :specimen";
969

    
970
        if(orderHints != null && orderHints.size() > 0){
971
            queryString += " ORDER BY ";
972
            String orderStr = "";
973
            for(OrderHint orderHint : orderHints){
974
                if(orderStr.length() > 0){
975
                    orderStr += ", ";
976
                }
977
                queryString += "designations." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
978
            }
979
            queryString += orderStr;
980
        }
981

    
982
        Query query = getSession().createQuery(queryString);
983
        query.setParameter("specimen", specimen);
984

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

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

    
1000
    @Override
1001
    public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1002
        //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
1003
        String queryString = "FROM IndividualsAssociation associations WHERE associations.associatedSpecimenOrObservation = :specimen";
1004

    
1005
        if(orderHints != null && orderHints.size() > 0){
1006
            queryString += " order by ";
1007
            String orderStr = "";
1008
            for(OrderHint orderHint : orderHints){
1009
                if(orderStr.length() > 0){
1010
                    orderStr += ", ";
1011
                }
1012
                queryString += "associations." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
1013
            }
1014
            queryString += orderStr;
1015
        }
1016

    
1017
        Query query = getSession().createQuery(queryString);
1018
        query.setParameter("specimen", specimen);
1019

    
1020
        if(limit != null) {
1021
            if(start != null) {
1022
                query.setFirstResult(start);
1023
            } else {
1024
                query.setFirstResult(0);
1025
            }
1026
            query.setMaxResults(limit);
1027
        }
1028

    
1029
        List results = query.list();
1030
        defaultBeanInitializer.initializeAll(results, propertyPaths);
1031
        return results;
1032
    }
1033

    
1034
    @Override
1035
    public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1036
        //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
1037
        String queryString = "FROM DescriptionBase descriptions WHERE descriptions.describedSpecimenOrObservation = :specimen";
1038

    
1039
        if(orderHints != null && orderHints.size() > 0){
1040
            queryString += " order by ";
1041
            String orderStr = "";
1042
            for(OrderHint orderHint : orderHints){
1043
                if(orderStr.length() > 0){
1044
                    orderStr += ", ";
1045
                }
1046
                queryString += "descriptions." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
1047
            }
1048
            queryString += orderStr;
1049
        }
1050

    
1051
        Query query = getSession().createQuery(queryString);
1052
        query.setParameter("specimen", specimen);
1053

    
1054
        if(limit != null) {
1055
            if(start != null) {
1056
                query.setFirstResult(start);
1057
            } else {
1058
                query.setFirstResult(0);
1059
            }
1060
            query.setMaxResults(limit);
1061
        }
1062

    
1063
        List results = query.list();
1064
        defaultBeanInitializer.initializeAll(results, propertyPaths);
1065
        return results;
1066
    }
1067

    
1068
    /**
1069
     * {@inheritDoc}
1070
     */
1071
    @Override
1072
    public List<FieldUnit> getFieldUnitsForGatheringEvent(UUID gatheringEventUuid, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1073
        String queryString = "FROM SpecimenOrObservationBase s WHERE s.gatheringEvent.uuid = :gatheringEventUuid";
1074

    
1075
        if(orderHints != null && orderHints.size() > 0){
1076
            queryString += " order by ";
1077
            String orderStr = "";
1078
            for(OrderHint orderHint : orderHints){
1079
                if(orderStr.length() > 0){
1080
                    orderStr += ", ";
1081
                }
1082
                queryString += "descriptions." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
1083
            }
1084
            queryString += orderStr;
1085
        }
1086

    
1087
        Query query = getSession().createQuery(queryString);
1088
        query.setParameter("gatheringEventUuid", gatheringEventUuid);
1089

    
1090
        if(limit != null) {
1091
            if(start != null) {
1092
                query.setFirstResult(start);
1093
            } else {
1094
                query.setFirstResult(0);
1095
            }
1096
            query.setMaxResults(limit);
1097
        }
1098

    
1099
        List results = query.list();
1100
        defaultBeanInitializer.initializeAll(results, propertyPaths);
1101
        return results;
1102
    }
1103

    
1104
}
(2-2/2)