Project

General

Profile

Download (45.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
package eu.etaxonomy.cdm.persistence.dao.hibernate.occurrence;
7

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

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

    
32
import eu.etaxonomy.cdm.model.common.CdmBase;
33
import eu.etaxonomy.cdm.model.description.DescriptionBase;
34
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
35
import eu.etaxonomy.cdm.model.location.Point;
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.MediaSpecimen;
46
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
47
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
48
import eu.etaxonomy.cdm.model.taxon.Synonym;
49
import eu.etaxonomy.cdm.model.taxon.Taxon;
50
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
51
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
52
import eu.etaxonomy.cdm.model.view.AuditEvent;
53
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
54
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;
55
import eu.etaxonomy.cdm.persistence.dao.hibernate.taxon.TaxonDaoHibernateImpl;
56
import eu.etaxonomy.cdm.persistence.dao.name.IHomotypicalGroupDao;
57
import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
58
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
59
import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
60
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
61
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
62
import eu.etaxonomy.cdm.persistence.query.MatchMode;
63
import eu.etaxonomy.cdm.persistence.query.OrderHint;
64

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

    
74
    private static final Logger logger = LogManager.getLogger(TaxonDaoHibernateImpl.class);
75

    
76
    @Autowired
77
    private IDescriptionDao descriptionDao;
78

    
79
    @Autowired
80
    private ITaxonNameDao taxonNameDao;
81

    
82
    @Autowired
83
    private IHomotypicalGroupDao homotypicalGroupDao;
84

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

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

    
99
        return query.uniqueResult();
100
    }
101

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

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

    
115
            criteria.setProjection(Projections.rowCount());
116
            return (Long)criteria.uniqueResult();
117
        } else {
118
            AuditQuery query = makeAuditQuery(DeterminationEvent.class,auditEvent);
119

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

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

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

    
133
    @Override
134
    public long countMedia(SpecimenOrObservationBase occurence) {
135
        return this.getMediaIds(occurence).size();
136
    }
137

    
138
    @Override
139
    public List<Media> getMedia(SpecimenOrObservationBase occurence,
140
            Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
141
        checkNotInPriorView("OccurrenceDaoHibernateImpl.getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths)");
142
        List<Integer> ids = this.getMediaIds(occurence);
143
        Query<Media> query = getSession().createQuery(
144
                "   SELECT m "
145
                + " FROM Media m "
146
                + " WHERE m.id in (:mediaIds)", Media.class);
147
        query.setParameterList("mediaIds", ids);
148

    
149
        addPageSizeAndNumber(query, pageSize, pageNumber);
150

    
151
        List<Media> results = query.list();
152
        defaultBeanInitializer.initializeAll(results, propertyPaths);
153
        return results;
154
    }
155

    
156
    private List<Integer> getMediaIds(SpecimenOrObservationBase occurence) {
157
        Query query = getSession().createQuery(
158
                "   SELECT DISTINCT m.id "
159
                + " FROM SpecimenOrObservationBase occ JOIN occ.descriptions d "
160
                + " JOIN d.descriptionElements el JOIN el.media m "
161
                + " WHERE occ = :occurence AND d.imageGallery = true "
162
                + " ORDER BY m.id ");
163
        query.setParameter("occurence", occurence);
164
        @SuppressWarnings("unchecked")
165
        List<Integer> list = query.list();
166

    
167
        if (occurence.isInstanceOf(MediaSpecimen.class)){
168
            String q2Str = " SELECT DISTINCT m.id "
169
                    + " FROM MediaSpecimen spec "
170
                    + " JOIN spec.mediaSpecimen m "
171
                    + " WHERE spec = :occurence ";
172
            Query<Integer> q2 = getSession().createQuery(q2Str, Integer.class);
173
            q2.setParameter("occurence", occurence);
174
            List<Integer> list2 = q2.list();
175
            list.addAll(list2);
176
            Set<Integer> dedupSet = new HashSet<>(list);
177
            list = new ArrayList<>(dedupSet);
178
            Collections.sort(list);
179
        }
180

    
181
        return list;
182
    }
183

    
184
    @Override
185
    public List<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {
186
        checkNotInPriorView("OccurrenceDaoHibernateImpl.getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber)");
187
        Query<DerivationEvent> query = getSession().createQuery("SELECT DISTINCT derivationEvent FROM DerivationEvent derivationEvent JOIN derivationEvent.originals occurence WHERE occurence = :occurence", DerivationEvent.class);
188
        query.setParameter("occurence", occurence);
189

    
190
        addPageSizeAndNumber(query, pageSize, pageNumber);
191

    
192
        List<DerivationEvent> result = query.list();
193
        defaultBeanInitializer.initializeAll(result, propertyPaths);
194
        return result;
195
    }
196

    
197
    @Override
198
    public List<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence,
199
            TaxonBase taxonBase, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
200
        AuditEvent auditEvent = getAuditEventFromContext();
201
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
202
            Criteria criteria = getSession().createCriteria(DeterminationEvent.class);
203
            if(occurrence != null) {
204
                criteria.add(Restrictions.eq("identifiedUnit",occurrence));
205
            }
206

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

    
211
            addPageSizeAndNumber(criteria, pageSize, pageNumber);
212

    
213
            @SuppressWarnings("unchecked")
214
            List<DeterminationEvent> result = criteria.list();
215
            defaultBeanInitializer.initializeAll(result, propertyPaths);
216
            return result;
217
        } else {
218
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());
219
            if(occurrence != null) {
220
                query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));
221
            }
222

    
223
            if(taxonBase != null) {
224
                query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));
225
            }
226
            addPageSizeAndNumber(query, pageSize, pageNumber);
227

    
228
            @SuppressWarnings("unchecked")
229
            List<DeterminationEvent> result = query.getResultList();
230
            defaultBeanInitializer.initializeAll(result, propertyPaths);
231
            return result;
232
        }
233
    }
234

    
235
    @Override
236
    public void rebuildIndex() {
237
        FullTextSession fullTextSession = Search.getFullTextSession(getSession());
238

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

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

    
268
    @Override
269
    public long count(Class<? extends SpecimenOrObservationBase> clazz,	TaxonName determinedAs) {
270

    
271
        Criteria criteria = getCriteria(clazz);
272

    
273
        criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));
274
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
275
        return (Long)criteria.uniqueResult();
276
    }
277

    
278
    @Override
279
    public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonName determinedAs,
280
            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
281
        Criteria criteria = getCriteria(clazz);
282

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

    
285
        addPageSizeAndNumber(criteria, pageSize, pageNumber);
286
        addOrder(criteria,orderHints);
287

    
288
        @SuppressWarnings({ "unchecked", "rawtypes" })
289
        List<SpecimenOrObservationBase> results = criteria.list();
290
        defaultBeanInitializer.initializeAll(results, propertyPaths);
291
        return results;
292
    }
293

    
294
    @Override
295
    public long count(Class<? extends SpecimenOrObservationBase> clazz,	TaxonBase determinedAs) {
296

    
297
        Criteria criteria = getCriteria(clazz);
298

    
299
        criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));
300
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
301
        return (Long)criteria.uniqueResult();
302
    }
303

    
304

    
305
    @Override
306
    public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonBase determinedAs,
307
            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
308

    
309
        Criteria criteria = getCriteria(clazz);
310

    
311
        criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));
312

    
313
        addPageSizeAndNumber(criteria, pageSize, pageNumber);
314
        addOrder(criteria,orderHints);
315

    
316
        @SuppressWarnings({ "unchecked", "rawtypes" })
317
        List<SpecimenOrObservationBase> results = criteria.list();
318
        defaultBeanInitializer.initializeAll(results, propertyPaths);
319
        return results;
320
    }
321

    
322
    @Override
323
    public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> findOccurrencesUuidAndTitleCache(
324
            Class<T> clazz, String queryString, String significantIdentifier, SpecimenOrObservationType recordBasis,
325
            Taxon associatedTaxon, TaxonName associatedTaxonName, MatchMode matchmode, Integer limit, Integer start,
326
            List<OrderHint> orderHints) {
327
        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
328
                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, null);
329
        if(criteria!=null){
330
            ProjectionList projectionList = Projections.projectionList();
331
            projectionList.add(Projections.property("uuid"));
332
            projectionList.add(Projections.property("id"));
333
            projectionList.add(Projections.property("titleCache"));
334
            criteria.setProjection(projectionList);
335

    
336
            @SuppressWarnings("unchecked")
337
            List<Object[]> result = criteria.list();
338
            List<UuidAndTitleCache<SpecimenOrObservationBase>> uuidAndTitleCacheList = new ArrayList<>();
339
            for(Object[] object : result){
340
                uuidAndTitleCacheList.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));
341
            }
342
            return uuidAndTitleCacheList;
343
        }else{
344
            return Collections.emptyList();
345
        }
346
    }
347

    
348
    @Override
349
    public <T extends SpecimenOrObservationBase> List<T> findOccurrences(Class<T> clazz, String queryString,
350
            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,
351
            MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
352

    
353
        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
354
                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);
355
        if(criteria!=null){
356
            @SuppressWarnings("unchecked")
357
            List<T> results = criteria.list();
358
            defaultBeanInitializer.initializeAll(results, propertyPaths);
359
            return results;
360
        }else{
361
            return Collections.emptyList();
362
        }
363
    }
364

    
365
    private <T extends SpecimenOrObservationBase> Criteria createFindOccurrenceCriteria(Class<T> clazz, String queryString,
366
            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon,
367
            TaxonName associatedTaxonName, MatchMode matchmode, Integer limit,
368
            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
369
        Criteria criteria = null;
370

    
371
        if(clazz == null) {
372
            criteria = getSession().createCriteria(type);
373
        } else {
374
            criteria = getSession().createCriteria(clazz);
375
        }
376

    
377
        //queryString
378
        if (queryString != null) {
379
            if(matchmode == null) {
380
                matchmode = MatchMode.ANYWHERE;
381
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString)));
382
            } else if(matchmode == MatchMode.BEGINNING) {
383
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.START));
384
            } else if(matchmode == MatchMode.END) {
385
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.END));
386
            } else if(matchmode == MatchMode.EXACT) {
387
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.EXACT));
388
            } else {
389
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.ANYWHERE));
390
            }
391
        }
392

    
393
        //significant identifier
394
        if (significantIdentifier != null) {
395
            criteria.add(Restrictions.or(Restrictions.ilike("accessionNumber", significantIdentifier),
396
                    Restrictions.ilike("catalogNumber", significantIdentifier), Restrictions.ilike("barcode", significantIdentifier)));
397
        }
398

    
399
        //recordBasis/SpecimenOrObservationType
400
        Set<SpecimenOrObservationType> typeAndSubtypes = new HashSet<>();
401
        if(recordBasis==null){
402
            //add all types
403
            SpecimenOrObservationType[] values = SpecimenOrObservationType.values();
404
            for (SpecimenOrObservationType specimenOrObservationType : values) {
405
                typeAndSubtypes.add(specimenOrObservationType);
406
            }
407
        }
408
        else{
409
            typeAndSubtypes = recordBasis.getGeneralizationOf(true);
410
            typeAndSubtypes.add(recordBasis);
411
        }
412
        criteria.add(Restrictions.in("recordBasis", typeAndSubtypes));
413

    
414
        Set<UUID> associationUuids = new HashSet<>();
415
        //taxon associations
416
        if(associatedTaxon!=null){
417
            List<UuidAndTitleCache<SpecimenOrObservationBase>> associatedTaxaList = listUuidAndTitleCacheByAssociatedTaxon(clazz, associatedTaxon, limit, start, orderHints);
418
            if(associatedTaxaList!=null){
419
                for (UuidAndTitleCache<SpecimenOrObservationBase> uuidAndTitleCache : associatedTaxaList) {
420
                    associationUuids.add(uuidAndTitleCache.getUuid());
421
                }
422
            }
423
        }
424
        //taxon name associations
425
        else if(associatedTaxonName!=null){
426
            List<? extends SpecimenOrObservationBase> associatedTaxaList = listByAssociatedTaxonName(clazz, associatedTaxonName, limit, start, orderHints, propertyPaths);
427
            if(associatedTaxaList!=null){
428
                for (SpecimenOrObservationBase<?> specimenOrObservationBase : associatedTaxaList) {
429
                    associationUuids.add(specimenOrObservationBase.getUuid());
430
                }
431
            }
432
        }
433
        if(associatedTaxon!=null || associatedTaxonName!=null){
434
            if(!associationUuids.isEmpty()){
435
                criteria.add(Restrictions.in("uuid", associationUuids));
436
            }
437
            else{
438
                return null;
439
            }
440
        }
441
        addLimitAndStart(criteria, limit, start);
442

    
443
        if(orderHints!=null){
444
            addOrder(criteria, orderHints);
445
        }
446
        return criteria;
447
    }
448

    
449

    
450
    @Override
451
    public <T extends SpecimenOrObservationBase> long countOccurrences(Class<T> clazz, String queryString,
452
            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,
453
            MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
454

    
455
        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
456
                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);
457

    
458
        if(criteria!=null){
459
            criteria.setProjection(Projections.rowCount());
460
            return (Long)criteria.uniqueResult();
461
        }else{
462
            return 0;
463
        }
464
    }
465

    
466
    @Override
467
    public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache(Integer limit, String pattern) {
468
        List<UuidAndTitleCache<DerivedUnit>> list = new ArrayList<>();
469
        Session session = getSession();
470
        String hql = "SELECT uuid, id, titleCache "
471
                + " FROM " + type.getSimpleName()
472
                + " WHERE NOT dtype = " + FieldUnit.class.getSimpleName();
473
        Query<Object[]> query;
474
        if (pattern != null){
475
            pattern = pattern.replace("*", "%");
476
            pattern = pattern.replace("?", "_");
477
            pattern = pattern + "%";
478
            query = session.createQuery(hql +" AND titleCache like :pattern", Object[].class);
479
            query.setParameter("pattern", pattern);
480
        } else {
481
            query = session.createQuery(hql, Object[].class);
482
        }
483
        if (limit != null){
484
           query.setMaxResults(limit);
485
        }
486

    
487
        List<Object[]> result = query.list();
488

    
489
        for(Object[] object : result){
490
            list.add(new UuidAndTitleCache<DerivedUnit>(DerivedUnit.class, (UUID) object[0], (Integer)object[1], (String) object[2]));
491
        }
492

    
493
        return list;
494
    }
495

    
496
    @Override
497
    public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
498
        List<UuidAndTitleCache<FieldUnit>> list = new ArrayList<>();
499

    
500
        Query<Object[]> query = getSession().createQuery("select uuid, id, titleCache from " + type.getSimpleName() + " where dtype = " + FieldUnit.class.getSimpleName(), Object[].class);
501

    
502
        List<Object[]> result = query.list();
503

    
504
        for(Object[] object : result){
505
            list.add(new UuidAndTitleCache<FieldUnit>(FieldUnit.class, (UUID) object[0], (Integer)object[1], (String) object[2]));
506
        }
507

    
508
        return list;
509
    }
510

    
511
    @Override
512
    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxonName(Class<T> type,
513
            TaxonName associatedTaxonName, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
514

    
515
        @SuppressWarnings("rawtypes")
516
        Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();
517

    
518
        // A Taxon name may be referenced by the DeterminationEvent of the SpecimenOrObservationBase
519
        @SuppressWarnings("rawtypes")
520
        List<SpecimenOrObservationBase> byDetermination = list(type, associatedTaxonName, null, 0, null, null);
521
        setOfAll.addAll(byDetermination);
522

    
523
        if(setOfAll.size() == 0){
524
            // no need querying the data base
525
            return new ArrayList<T>();
526
        }
527

    
528
        String queryString =
529
            "SELECT sob " +
530
            " FROM SpecimenOrObservationBase sob" +
531
            " WHERE sob in (:setOfAll)";
532

    
533
        if(type != null && !type.equals(SpecimenOrObservationBase.class)){
534
            queryString += " AND sob.class = :type";
535
        }
536
        queryString += orderByClause("sob", orderHints);
537

    
538
        @SuppressWarnings("unchecked")
539
        Query<T> query = getSession().createQuery(queryString);
540
        query.setParameterList("setOfAll", setOfAll);
541

    
542
        if(type != null && !type.equals(SpecimenOrObservationBase.class)){
543
            query.setParameter("type", type.getSimpleName());
544
        }
545

    
546
        addLimitAndStart(query, limit, start);
547

    
548
        @SuppressWarnings("unchecked")
549
        List<T> results = query.list();
550
        defaultBeanInitializer.initializeAll(results, propertyPaths);
551
        return results;
552
    }
553

    
554
    private List<SpecimenNodeWrapper> querySpecimen(Query<Object[]> query, List<UUID> taxonNodeUuids,
555
            Integer limit, Integer start){
556
        query.setParameterList("taxonNodeUuids", taxonNodeUuids);
557

    
558
        addLimitAndStart(query, limit, start);
559

    
560
        List<SpecimenNodeWrapper> list = new ArrayList<>();
561
        List<Object[]> result = query.list();
562
        for(Object[] object : result){
563
            SpecimenNodeWrapper wrapper = new SpecimenNodeWrapper(
564
                    new UuidAndTitleCache<>(
565
                            (UUID) object[0],
566
                            (Integer) object[1],
567
                            (String) object[2]),
568
                    (SpecimenOrObservationType)object[3],
569
                    new TaxonNodeDto((TaxonNode)object[4]));
570
            if(object.length>5) {
571
                wrapper.setTaxonDescriptionUuid((UUID)object[5]);
572
            }
573
            list.add(wrapper);
574
        }
575
        return list;
576
    }
577

    
578
    private List<SpecimenNodeWrapper> queryIndividualAssociatedSpecimen(List<UUID> taxonNodeUuids,
579
            Integer limit, Integer start){
580
        String queryString =  "SELECT "
581
                + "de.associatedSpecimenOrObservation.uuid, "
582
                + "de.associatedSpecimenOrObservation.id, "
583
                + "de.associatedSpecimenOrObservation.titleCache, "
584
                + "de.associatedSpecimenOrObservation.recordBasis, "
585
                + "tn, "
586
                + "d.uuid "
587
                + "FROM DescriptionElementBase AS de "
588
                + "LEFT JOIN de.inDescription AS d "
589
                + "LEFT JOIN d.taxon AS t "
590
                + "JOIN t.taxonNodes AS tn "
591
                + "WHERE d.class = 'TaxonDescription' "
592
                + "AND tn.uuid in (:taxonNodeUuids) "
593
                ;
594
        Query<Object[]> query = getSession().createQuery(queryString, Object[].class);
595
        return querySpecimen(query, taxonNodeUuids, limit, start);
596
    }
597

    
598
    private List<SpecimenNodeWrapper> queryTypeSpecimen(List<UUID> taxonNodeUuids,
599
            Integer limit, Integer start){
600
        String queryString =  "SELECT "
601
                + "td.typeSpecimen.uuid, "
602
                + "td.typeSpecimen.id, "
603
                + "td.typeSpecimen.titleCache, "
604
                + "td.typeSpecimen.recordBasis, "
605
                + "tn "
606
                + "FROM SpecimenTypeDesignation AS td "
607
                + "LEFT JOIN td.typifiedNames AS tn "
608
                + "LEFT JOIN tn.taxonBases AS t "
609
                + "JOIN t.taxonNodes AS tn "
610
                + "WHERE tn.uuid in (:taxonNodeUuids) "
611
                ;
612
        Query<Object[]> query = getSession().createQuery(queryString, Object[].class);
613
        return querySpecimen(query, taxonNodeUuids, limit, start);
614
    }
615

    
616
    private List<SpecimenNodeWrapper> queryTaxonDeterminations(List<UUID> taxonNodeUuids,
617
            Integer limit, Integer start){
618
        String queryString =  "SELECT "
619
                + "det.identifiedUnit.uuid, "
620
                + "det.identifiedUnit.id, "
621
                + "det.identifiedUnit.titleCache, "
622
                + "det.identifiedUnit.recordBasis, "
623
                + "tn "
624
                + "FROM DeterminationEvent AS det "
625
                + "LEFT JOIN det.taxon AS t "
626
                + "JOIN t.taxonNodes AS tn "
627
                + "WHERE tn.uuid in (:taxonNodeUuids) "
628
                ;
629
        Query<Object[]> query = getSession().createQuery(queryString, Object[].class);
630
        return querySpecimen(query, taxonNodeUuids, limit, start);
631
    }
632

    
633
    private List<SpecimenNodeWrapper> queryTaxonNameDeterminations(List<UUID> taxonNodeUuids,
634
            Integer limit, Integer start){
635
        String queryString =  "SELECT "
636
                + "det.identifiedUnit.uuid, "
637
                + "det.identifiedUnit.id, "
638
                + "det.identifiedUnit.titleCache, "
639
                + "det.identifiedUnit.recordBasis, "
640
                + "tn "
641
                + "FROM DeterminationEvent AS det "
642
                + "LEFT JOIN det.taxonName AS n "
643
                + "LEFT JOIN n.taxonBases AS t "
644
                + "JOIN t.taxonNodes AS tn "
645
                + "WHERE tn.uuid in (:taxonNodeUuids) "
646
                ;
647
        Query<Object[]> query = getSession().createQuery(queryString, Object[].class);
648
        return querySpecimen(query, taxonNodeUuids, limit, start);
649
    }
650

    
651
    @Override
652
    public Collection<SpecimenNodeWrapper> listUuidAndTitleCacheByAssociatedTaxon(List<UUID> taxonNodeUuids,
653
            Integer limit, Integer start){
654

    
655
        Set<SpecimenNodeWrapper> testSet = new HashSet<>();
656

    
657
        testSet.addAll(queryIndividualAssociatedSpecimen(taxonNodeUuids, limit, start));
658
        testSet.addAll(queryTaxonDeterminations(taxonNodeUuids, limit, start));
659
        testSet.addAll(queryTaxonNameDeterminations(taxonNodeUuids, limit, start));
660
        testSet.addAll(queryTypeSpecimen(taxonNodeUuids, limit, start));
661

    
662
        Collection<SpecimenNodeWrapper> wrappers = new HashSet<>();
663
        wrappers.addAll(testSet);
664
        return wrappers;
665
    }
666

    
667
    @Override
668
    public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> listUuidAndTitleCacheByAssociatedTaxon(Class<T> clazz, Taxon associatedTaxon,
669
            Integer limit, Integer start, List<OrderHint> orderHints){
670
        Query<Object[]> query = createSpecimenQuery("sob.uuid, sob.id, sob.titleCache", clazz, associatedTaxon, limit, start, orderHints, Object[].class);
671
        if(query==null){
672
            return Collections.emptyList();
673
        }
674
        List<UuidAndTitleCache<SpecimenOrObservationBase>> list = new ArrayList<>();
675
        List<Object[]> result = query.list();
676
        for(Object[] object : result){
677
            list.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));
678
        }
679
        return list;
680
    }
681

    
682
    @Override
683
    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> clazz,
684
            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
685

    
686
        @SuppressWarnings("rawtypes")
687
        Query<SpecimenOrObservationBase> query = createSpecimenQuery("sob", clazz, associatedTaxon, limit, start, orderHints, SpecimenOrObservationBase.class);
688
        if(query==null){
689
            return Collections.emptyList();
690
        }
691

    
692
        @SuppressWarnings({ "unchecked", "rawtypes" })
693
        List<T> results = (List)query.list();
694
        defaultBeanInitializer.initializeAll(results, propertyPaths);
695
        return results;
696
    }
697

    
698
    private <T extends SpecimenOrObservationBase, R extends Object> Query<R> createSpecimenQuery(String select, Class<T> clazz,
699
            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, Class<R> returnClass){
700
//        Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();
701
        Set<Integer> setOfAllIds = new HashSet<>();
702

    
703
        Criteria criteria = null;
704
        if(clazz == null) {
705
            criteria = getSession().createCriteria(type, "specimen");
706
        } else {
707
            criteria = getSession().createCriteria(clazz, "specimen");
708
        }
709

    
710
        Disjunction determinationOr = Restrictions.disjunction();
711

    
712
        // A Taxon may be referenced by the DeterminationEvent of the SpecimenOrObservationBase
713
        Criteria determinationsCriteria = criteria.createCriteria("determinations");
714

    
715
        determinationOr.add(Restrictions.eq("taxon", associatedTaxon));
716
        //check also for synonyms
717
        for (Synonym synonym : associatedTaxon.getSynonyms()) {
718
            determinationOr.add(Restrictions.eq("taxon", synonym));
719
        }
720

    
721
        //check also for name determinations
722
        determinationOr.add(Restrictions.eq("taxonName", associatedTaxon.getName()));
723
        for (TaxonName synonymName : associatedTaxon.getSynonymNames()) {
724
            determinationOr.add(Restrictions.eq("taxonName", synonymName));
725
        }
726

    
727
        determinationsCriteria.add(determinationOr);
728

    
729
        if(limit != null) {
730
            if(start != null) {
731
                criteria.setFirstResult(start);
732
            } else {
733
                criteria.setFirstResult(0);
734
            }
735
            criteria.setMaxResults(limit);
736
        }
737
        criteria.setProjection(Projections.property("id"));
738

    
739
        addOrder(criteria,orderHints);
740

    
741
        @SuppressWarnings("unchecked")
742
        List<Integer> detResults = criteria.list();
743
        setOfAllIds.addAll(detResults);
744

    
745
        // The IndividualsAssociation elements in a TaxonDescription contain DerivedUnits
746
        setOfAllIds.addAll(descriptionDao.getIndividualAssociationSpecimenIDs(
747
                associatedTaxon.getUuid(), null, null, 0, null));
748

    
749

    
750
        // SpecimenTypeDesignations may be associated with the TaxonName.
751
        setOfAllIds.addAll(taxonNameDao.getTypeSpecimenIdsForTaxonName(
752
                associatedTaxon.getName(), null, null, null));
753

    
754
        // SpecimenTypeDesignations may be associated with any HomotypicalGroup related to the specific Taxon.
755
        //TODO adapt to set of ids
756
        for(HomotypicalGroup homotypicalGroup :  associatedTaxon.getHomotypicSynonymyGroups()) {
757
            List<SpecimenTypeDesignation> byHomotypicalGroup = homotypicalGroupDao.getTypeDesignations(homotypicalGroup, SpecimenTypeDesignation.class, null, null, 0, null);
758
            for (SpecimenTypeDesignation specimenTypeDesignation : byHomotypicalGroup) {
759
                if (specimenTypeDesignation.getTypeSpecimen() != null){
760
                    setOfAllIds.add(specimenTypeDesignation.getTypeSpecimen().getId());
761
                }
762
            }
763
        }
764

    
765
        if(setOfAllIds.size() == 0){
766
            // no need querying the data base
767
            return null;
768
        }
769

    
770
        String queryString =
771
            "select "+select+
772
            " from SpecimenOrObservationBase sob" +
773
            " where sob.id in (:setOfAllIds)";
774

    
775
        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
776
            queryString += " and sob.class = :type ";
777
        }
778

    
779
        if(orderHints != null && orderHints.size() > 0){
780
            queryString += " order by ";
781
            String orderStr = "";
782
            for(OrderHint orderHint : orderHints){
783
                if(orderStr.length() > 0){
784
                    orderStr += ", ";
785
                }
786
                queryString += "sob." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
787
            }
788
            queryString += orderStr;
789
        }
790

    
791
        Query<R> query = getSession().createQuery(queryString, returnClass);
792
        query.setParameterList("setOfAllIds", setOfAllIds);
793

    
794
        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
795
            query.setParameter("type", clazz.getSimpleName());
796
        }
797

    
798
        addLimitAndStart(query, limit, start);
799

    
800
        return query;
801
    }
802

    
803
    @Override
804
    public Collection<SpecimenOrObservationBase> listBySpecimenOrObservationType(SpecimenOrObservationType type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
805
        String queryString = "FROM SpecimenOrObservationBase specimens "
806
                + " WHERE specimens.recordBasis = :type ";
807

    
808
        queryString += orderByClause("specimens", orderHints);
809

    
810
        Query<SpecimenOrObservationBase> query = getSession().createQuery(queryString, SpecimenOrObservationBase.class);
811
        query.setParameter("type", type);
812

    
813
        addLimitAndStart(query, limit, start);
814

    
815
        @SuppressWarnings("rawtypes")
816
        List<SpecimenOrObservationBase> results = query.list();
817
        defaultBeanInitializer.initializeAll(results, propertyPaths);
818
        return results;
819
    }
820

    
821

    
822
    @Override
823
    public Collection<DeterminationEvent> listDeterminationEvents(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
824
        String queryString = "FROM DeterminationEvent determination "
825
                + " WHERE determination.identifiedUnit = :specimen";
826

    
827
        queryString += orderByClause("determination", orderHints);
828

    
829
        Query<DeterminationEvent> query = getSession().createQuery(queryString, DeterminationEvent.class);
830
        query.setParameter("specimen", specimen);
831

    
832
        addLimitAndStart(query, limit, start);
833

    
834
        List<DeterminationEvent> results = query.list();
835
        defaultBeanInitializer.initializeAll(results, propertyPaths);
836
        return results;
837
    }
838

    
839
    @Override
840
    public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
841
        String queryString = "FROM SpecimenTypeDesignation designations "
842
                + " WHERE designations.typeSpecimen = :specimen";
843

    
844
        queryString += orderByClause("designations", orderHints);
845

    
846
        Query<SpecimenTypeDesignation> query = getSession().createQuery(queryString, SpecimenTypeDesignation.class);
847
        query.setParameter("specimen", specimen);
848

    
849
        addLimitAndStart(query, limit, start);
850

    
851
        List<SpecimenTypeDesignation> results = query.list();
852
        defaultBeanInitializer.initializeAll(results, propertyPaths);
853
        return results;
854
    }
855

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

    
861
        queryString += orderByClause("associations", orderHints);
862

    
863
        Query<IndividualsAssociation> query = getSession().createQuery(queryString, IndividualsAssociation.class);
864
        query.setParameter("specimen", specimen);
865

    
866
        addLimitAndStart(query, limit, start);
867

    
868
        List<IndividualsAssociation> results = query.list();
869
        defaultBeanInitializer.initializeAll(results, propertyPaths);
870
        return results;
871
    }
872

    
873
    @Override
874
    public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
875
        //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
876
        String queryString = "FROM DescriptionBase descriptions "
877
                + " WHERE descriptions.describedSpecimenOrObservation = :specimen";
878

    
879
        queryString += orderByClause("descriptions", orderHints);
880

    
881
        Query<DescriptionBase<?>> query = getSession().createQuery(queryString);
882
        query.setParameter("specimen", specimen);
883

    
884
        addLimitAndStart(query, limit, start);
885

    
886
        List<DescriptionBase<?>> results = query.list();
887
        defaultBeanInitializer.initializeAll(results, propertyPaths);
888
        return results;
889
    }
890

    
891
    @Override
892
    public List<FieldUnit> findFieldUnitsForGatheringEvent(UUID gatheringEventUuid, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
893
        String queryString = "FROM SpecimenOrObservationBase sob "
894
                + "WHERE sob.gatheringEvent.uuid = :gatheringEventUuid";
895

    
896
        queryString += orderByClause("sob", orderHints);
897

    
898
        Query<FieldUnit> query = getSession().createQuery(queryString, FieldUnit.class);
899
        query.setParameter("gatheringEventUuid", gatheringEventUuid);
900

    
901
        addLimitAndStart(query, limit, start);
902

    
903
        List<FieldUnit> results = query.list();
904
        defaultBeanInitializer.initializeAll(results, propertyPaths);
905
        return results;
906
    }
907

    
908
    @Override
909
    public DnaSample findByGeneticAccessionNumber(String accessionNumberString, List<String> propertyPaths) {
910
        String queryString = "SELECT dnaSample FROM DnaSample as dnaSample join dnaSample.sequences as sequences WITH sequences.geneticAccessionNumber LIKE :accessionNumberString";
911
        Query query = getSession().createQuery(queryString);
912
        query.setParameter("accessionNumberString", accessionNumberString);
913
        @SuppressWarnings("unchecked")
914
        List<DnaSample> dnaSamples = query.list();
915
        defaultBeanInitializer.initializeAll(dnaSamples, propertyPaths);
916

    
917
        if (dnaSamples.isEmpty()){
918
            logger.debug("there is no dnaSample for genetic accession number " + accessionNumberString + " this should not happen.");
919
            return null;
920
        }else if (dnaSamples.size() == 1){
921
            return dnaSamples.get(0);
922
        } else{
923
            logger.debug("there are more than one dnaSample for genetic accession number " + accessionNumberString + " this should not happen.");
924
            return null;
925
        }
926
    }
927

    
928
   @Override
929
   public long countByGeneticAccessionNumber(String accessionNumberString) {
930
       String queryString = "SELECT count(dnaSample) FROM DnaSample dnaSample JOIN dnaSample.sequences sequence WHERE sequence.geneticAccessionNumber LIKE :accessionNumberString";
931
       Query<Long> query = getSession().createQuery(queryString, Long.class);
932
       query.setParameter("accessionNumberString", accessionNumberString);
933
       long result = query.uniqueResult();
934
       return result;
935
   }
936

    
937
    private void extractDeterminedOriginals(List<DerivedUnit> samples, List<DerivedUnit> results) {
938
        for (DerivedUnit sample:samples){
939
            if (sample.getDeterminations() != null && !sample.getDeterminations().isEmpty()){
940
                results.add(sample);
941
            }else{
942
                if (sample instanceof DerivedUnit){
943
                    Set<SpecimenOrObservationBase> originals = sample.getDerivedFrom().getOriginals();
944
                    List<DerivedUnit> originalDerivedUnits = new ArrayList<>();
945
                    for (SpecimenOrObservationBase original: originals){
946
                        if (original instanceof DerivedUnit){
947
                            originalDerivedUnits.add((DerivedUnit)original);
948
                        }
949
                    }
950
                    if(!originalDerivedUnits.isEmpty()){
951
                        extractDeterminedOriginals(originalDerivedUnits, results);
952
                    }
953
                }
954
            }
955
        }
956
    }
957

    
958
    @Override
959
    public List<SpecimenOrObservationBase> findOriginalsForDerivedUnit(UUID derivedUnitUuid, List<String> propertyPaths) {
960
        String queryString = "SELECT DISTINCT o FROM DerivedUnit du"
961
                + " JOIN du.derivedFrom.originals o WHERE du.uuid LIKE :derivedUnitUuid";
962
        Query<SpecimenOrObservationBase> query = getSession().createQuery(queryString, SpecimenOrObservationBase.class);
963
        query.setParameter("derivedUnitUuid", derivedUnitUuid);
964
        List<SpecimenOrObservationBase> results = query.list();
965
        defaultBeanInitializer.initializeAll(results, propertyPaths);
966
        return results;
967
    }
968

    
969
    @Override
970
    public List<Point> findPointsForFieldUnitList(List<UUID> fieldUnitUuids) {
971
        String queryString = "SELECT DISTINCT fu.gatheringEvent.exactLocation FROM FieldUnit fu"
972
                + "  WHERE fu.uuid IN (:fieldUnitUuids)";
973
        Query<Point> query = getSession().createQuery(queryString, Point.class);
974
        query.setParameterList("fieldUnitUuids", fieldUnitUuids);
975
        List<Point> results = query.list();
976

    
977
        return results;
978
    }
979

    
980
    @Override
981
    public String findMostSignificantIdentifier(UUID derivedUnitUuid) {
982

    
983
        String queryString = "SELECT du.catalogNumber, du.accessionNumber, du.barcode FROM DerivedUnit du"
984
                + " WHERE du.uuid LIKE :derivedUnitUuid";
985
        Query<String[]> query = getSession().createQuery(queryString, String[].class);
986
        query.setParameter("derivedUnitUuid", derivedUnitUuid);
987
        List<String[]> results = query.list();
988
        if (results.isEmpty()){
989
            return null;
990
        }
991
        Object[] stringResult = results.get(0);
992
        if (stringResult[1] != null && stringResult[1] instanceof String){
993
            return (String)stringResult[1];
994
        }
995
        if (stringResult[2] != null && stringResult[2] instanceof String){
996
            return (String)stringResult[2];
997
        }
998
        if (stringResult[0] != null && stringResult[0] instanceof String){
999
            return (String)stringResult[0];
1000
        }
1001

    
1002
        return null;
1003
    }
1004

    
1005
}
(2-2/2)