Project

General

Profile

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

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

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

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

    
33
import eu.etaxonomy.cdm.model.common.CdmBase;
34
import eu.etaxonomy.cdm.model.description.DescriptionBase;
35
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
36
import eu.etaxonomy.cdm.model.location.Point;
37
import eu.etaxonomy.cdm.model.media.Media;
38
import eu.etaxonomy.cdm.model.molecular.DnaSample;
39
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
40
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
41
import eu.etaxonomy.cdm.model.name.TaxonName;
42
import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
43
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
44
import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
45
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
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.UuidAndTitleCache;
61
import eu.etaxonomy.cdm.persistence.query.MatchMode;
62
import eu.etaxonomy.cdm.persistence.query.OrderHint;
63

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

    
73
    @SuppressWarnings("unused")
74
    private static final Logger logger = Logger.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 query = getSession().createQuery("select count(distinct derivationEvent) from DerivationEvent derivationEvent join derivationEvent.originals occurence where occurence = :occurence");
97
        query.setParameter("occurence", occurence);
98

    
99
        return (Long)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
        checkNotInPriorView("OccurrenceDaoHibernateImpl.countMedia(SpecimenOrObservationBase occurence)");
136
        Query query = getSession().createQuery("select count(media) from SpecimenOrObservationBase occurence join occurence.media media where occurence = :occurence");
137
        query.setParameter("occurence", occurence);
138

    
139
        return (Long)query.uniqueResult();
140
    }
141

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

    
148
        addPageSizeAndNumber(query, pageSize, pageNumber);
149

    
150
        @SuppressWarnings("unchecked")
151
        List<DerivationEvent> result = query.list();
152
        defaultBeanInitializer.initializeAll(result, propertyPaths);
153
        return result;
154
    }
155

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

    
165
            if(taxonBase != null) {
166
                criteria.add(Restrictions.eq("taxon",taxonBase));
167
            }
168

    
169
            addPageSizeAndNumber(criteria, pageSize, pageNumber);
170

    
171
            @SuppressWarnings("unchecked")
172
            List<DeterminationEvent> result = criteria.list();
173
            defaultBeanInitializer.initializeAll(result, propertyPaths);
174
            return result;
175
        } else {
176
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());
177
            if(occurrence != null) {
178
                query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));
179
            }
180

    
181
            if(taxonBase != null) {
182
                query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));
183
            }
184
            addPageSizeAndNumber(query, pageSize, pageNumber);
185

    
186
            @SuppressWarnings("unchecked")
187
            List<DeterminationEvent> result = query.getResultList();
188
            defaultBeanInitializer.initializeAll(result, propertyPaths);
189
            return result;
190
        }
191
    }
192

    
193
    @Override
194
    public List<Media> getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
195
        checkNotInPriorView("OccurrenceDaoHibernateImpl.getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths)");
196
        Query query = getSession().createQuery(
197
                "   SELECT media "
198
                + " FROM SpecimenOrObservationBase occurence "
199
                + " JOIN occurence.media media "
200
                + " WHERE occurence = :occurence");
201
        query.setParameter("occurence", occurence);
202

    
203
        addPageSizeAndNumber(query, pageSize, pageNumber);
204

    
205
        @SuppressWarnings("unchecked")
206
        List<Media> results = query.list();
207
        defaultBeanInitializer.initializeAll(results, propertyPaths);
208
        return results;
209
    }
210

    
211
    @Override
212
    public void rebuildIndex() {
213
        FullTextSession fullTextSession = Search.getFullTextSession(getSession());
214

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

    
217
            for(DeterminationEvent determination : occurrence.getDeterminations()) {
218
                Hibernate.initialize(determination.getActor());
219
                Hibernate.initialize(determination.getTaxon());
220
            }
221
            Hibernate.initialize(occurrence.getDefinition());
222
            if(occurrence instanceof DerivedUnit) {
223
                DerivedUnit derivedUnit = (DerivedUnit) occurrence;
224
                Hibernate.initialize(derivedUnit.getCollection());
225
                if(derivedUnit.getCollection() != null) {
226
                    Hibernate.initialize(derivedUnit.getCollection().getSuperCollection());
227
                    Hibernate.initialize(derivedUnit.getCollection().getInstitute());
228
                }
229
                Hibernate.initialize(derivedUnit.getStoredUnder());
230
                SpecimenOrObservationBase<?> original = derivedUnit.getOriginalUnit();
231
                if(original != null && original.isInstanceOf(FieldUnit.class)) {
232
                    FieldUnit fieldUnit = CdmBase.deproxy(original, FieldUnit.class);
233
                    Hibernate.initialize(fieldUnit.getGatheringEvent());
234
                    if(fieldUnit.getGatheringEvent() != null) {
235
                        Hibernate.initialize(fieldUnit.getGatheringEvent().getActor());
236
                    }
237
                }
238
            }
239
            fullTextSession.index(occurrence);
240
        }
241
        fullTextSession.flushToIndexes();
242
    }
243

    
244
    @Override
245
    public long count(Class<? extends SpecimenOrObservationBase> clazz,	TaxonName determinedAs) {
246

    
247
        Criteria criteria = getCriteria(clazz);
248

    
249
        criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));
250
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
251
        return (Long)criteria.uniqueResult();
252
    }
253

    
254
    @Override
255
    public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonName determinedAs,
256
            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
257
        Criteria criteria = getCriteria(clazz);
258

    
259
        criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));
260

    
261
        addPageSizeAndNumber(criteria, pageSize, pageNumber);
262
        addOrder(criteria,orderHints);
263

    
264
        @SuppressWarnings({ "unchecked", "rawtypes" })
265
        List<SpecimenOrObservationBase> results = criteria.list();
266
        defaultBeanInitializer.initializeAll(results, propertyPaths);
267
        return results;
268
    }
269

    
270
    @Override
271
    public long count(Class<? extends SpecimenOrObservationBase> clazz,	TaxonBase determinedAs) {
272

    
273
        Criteria criteria = getCriteria(clazz);
274

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

    
280

    
281
    @Override
282
    public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonBase determinedAs,
283
            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
284

    
285
        Criteria criteria = getCriteria(clazz);
286

    
287
        criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));
288

    
289
        addPageSizeAndNumber(criteria, pageSize, pageNumber);
290
        addOrder(criteria,orderHints);
291

    
292
        @SuppressWarnings({ "unchecked", "rawtypes" })
293
        List<SpecimenOrObservationBase> results = criteria.list();
294
        defaultBeanInitializer.initializeAll(results, propertyPaths);
295
        return results;
296
    }
297

    
298
    @Override
299
    public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> findOccurrencesUuidAndTitleCache(
300
            Class<T> clazz, String queryString, String significantIdentifier, SpecimenOrObservationType recordBasis,
301
            Taxon associatedTaxon, TaxonName associatedTaxonName, MatchMode matchmode, Integer limit, Integer start,
302
            List<OrderHint> orderHints) {
303
        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
304
                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, null);
305
        if(criteria!=null){
306
            ProjectionList projectionList = Projections.projectionList();
307
            projectionList.add(Projections.property("uuid"));
308
            projectionList.add(Projections.property("id"));
309
            projectionList.add(Projections.property("titleCache"));
310
            criteria.setProjection(projectionList);
311

    
312
            @SuppressWarnings("unchecked")
313
            List<Object[]> result = criteria.list();
314
            List<UuidAndTitleCache<SpecimenOrObservationBase>> uuidAndTitleCacheList = new ArrayList<>();
315
            for(Object[] object : result){
316
                uuidAndTitleCacheList.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));
317
            }
318
            return uuidAndTitleCacheList;
319
        }else{
320
            return Collections.emptyList();
321
        }
322
    }
323

    
324
    @Override
325
    public <T extends SpecimenOrObservationBase> List<T> findOccurrences(Class<T> clazz, String queryString,
326
            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,
327
            MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
328

    
329
        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
330
                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);
331
        if(criteria!=null){
332
            @SuppressWarnings("unchecked")
333
            List<T> results = criteria.list();
334
            defaultBeanInitializer.initializeAll(results, propertyPaths);
335
            return results;
336
        }else{
337
            return Collections.emptyList();
338
        }
339
    }
340

    
341
    private <T extends SpecimenOrObservationBase> Criteria createFindOccurrenceCriteria(Class<T> clazz, String queryString,
342
            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName, MatchMode matchmode, Integer limit,
343
            Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
344
        Criteria criteria = null;
345

    
346
        if(clazz == null) {
347
            criteria = getSession().createCriteria(type);
348
        } else {
349
            criteria = getSession().createCriteria(clazz);
350
        }
351

    
352
        //queryString
353
        if (queryString != null) {
354
            if(matchmode == null) {
355
                matchmode = MatchMode.ANYWHERE;
356
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString)));
357
            } else if(matchmode == MatchMode.BEGINNING) {
358
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.START));
359
            } else if(matchmode == MatchMode.END) {
360
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.END));
361
            } else if(matchmode == MatchMode.EXACT) {
362
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.EXACT));
363
            } else {
364
                criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.ANYWHERE));
365
            }
366
        }
367

    
368
        //significant identifier
369
        if (significantIdentifier != null) {
370
            criteria.add(Restrictions.or(Restrictions.ilike("accessionNumber", significantIdentifier),
371
                    Restrictions.ilike("catalogNumber", significantIdentifier), Restrictions.ilike("barcode", significantIdentifier)));
372
        }
373

    
374
        //recordBasis/SpecimenOrObservationType
375
        Set<SpecimenOrObservationType> typeAndSubtypes = new HashSet<SpecimenOrObservationType>();
376
        if(recordBasis==null){
377
            //add all types
378
            SpecimenOrObservationType[] values = SpecimenOrObservationType.values();
379
            for (SpecimenOrObservationType specimenOrObservationType : values) {
380
                typeAndSubtypes.add(specimenOrObservationType);
381
            }
382
        }
383
        else{
384
            typeAndSubtypes = recordBasis.getGeneralizationOf(true);
385
            typeAndSubtypes.add(recordBasis);
386
        }
387
        criteria.add(Restrictions.in("recordBasis", typeAndSubtypes));
388

    
389
        Set<UUID> associationUuids = new HashSet<UUID>();
390
        //taxon associations
391
        if(associatedTaxon!=null){
392
            List<UuidAndTitleCache<SpecimenOrObservationBase>> associatedTaxaList = listUuidAndTitleCacheByAssociatedTaxon(clazz, associatedTaxon, limit, start, orderHints);
393
            if(associatedTaxaList!=null){
394
                for (UuidAndTitleCache<SpecimenOrObservationBase> uuidAndTitleCache : associatedTaxaList) {
395
                    associationUuids.add(uuidAndTitleCache.getUuid());
396
                }
397
            }
398
        }
399
        //taxon name associations
400
        else if(associatedTaxonName!=null){
401
            List<? extends SpecimenOrObservationBase> associatedTaxaList = listByAssociatedTaxonName(clazz, associatedTaxonName, limit, start, orderHints, propertyPaths);
402
            if(associatedTaxaList!=null){
403
                for (SpecimenOrObservationBase<?> specimenOrObservationBase : associatedTaxaList) {
404
                    associationUuids.add(specimenOrObservationBase.getUuid());
405
                }
406
            }
407
        }
408
        if(associatedTaxon!=null || associatedTaxonName!=null){
409
            if(!associationUuids.isEmpty()){
410
                criteria.add(Restrictions.in("uuid", associationUuids));
411
            }
412
            else{
413
                return null;
414
            }
415
        }
416
        if(limit != null) {
417
            if(start != null) {
418
                criteria.setFirstResult(start);
419
            } else {
420
                criteria.setFirstResult(0);
421
            }
422
            criteria.setMaxResults(limit);
423
        }
424

    
425
        if(orderHints!=null){
426
            addOrder(criteria,orderHints);
427
        }
428
        return criteria;
429
    }
430

    
431

    
432
    @Override
433
    public <T extends SpecimenOrObservationBase> long countOccurrences(Class<T> clazz, String queryString,
434
            String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,
435
            MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
436

    
437
        Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
438
                associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);
439

    
440
        if(criteria!=null){
441
            criteria.setProjection(Projections.rowCount());
442
            return (Long)criteria.uniqueResult();
443
        }else{
444
            return 0;
445
        }
446
    }
447

    
448
    @Override
449
    public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache(Integer limit, String pattern) {
450
        List<UuidAndTitleCache<DerivedUnit>> list = new ArrayList<>();
451
        Session session = getSession();
452
        String hql = "SELECT uuid, id, titleCache "
453
                + " FROM " + type.getSimpleName()
454
                + " WHERE NOT dtype = " + FieldUnit.class.getSimpleName();
455
        Query query;
456
        if (pattern != null){
457
            pattern = pattern.replace("*", "%");
458
            pattern = pattern.replace("?", "_");
459
            pattern = pattern + "%";
460
            query = session.createQuery(hql +" AND titleCache like :pattern");
461
            query.setParameter("pattern", pattern);
462
        } else {
463
            query = session.createQuery(hql);
464
        }
465
        if (limit != null){
466
           query.setMaxResults(limit);
467
        }
468

    
469
        @SuppressWarnings("unchecked")
470
        List<Object[]> result = query.list();
471

    
472
        for(Object[] object : result){
473
            list.add(new UuidAndTitleCache<DerivedUnit>(DerivedUnit.class, (UUID) object[0], (Integer)object[1], (String) object[2]));
474
        }
475

    
476
        return list;
477
    }
478

    
479
    @Override
480
    public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
481
        List<UuidAndTitleCache<FieldUnit>> list = new ArrayList<>();
482
        Session session = getSession();
483

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

    
486
        @SuppressWarnings("unchecked")
487
        List<Object[]> result = query.list();
488

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

    
493
        return list;
494
    }
495

    
496
    @Override
497
    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxonName(Class<T> type,
498
            TaxonName associatedTaxonName, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
499

    
500
        @SuppressWarnings("rawtypes")
501
        Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();
502

    
503
        // A Taxon name may be referenced by the DeterminationEvent of the SpecimenOrObservationBase
504
        @SuppressWarnings("rawtypes")
505
        List<SpecimenOrObservationBase> byDetermination = list(type, associatedTaxonName, null, 0, null, null);
506
        setOfAll.addAll(byDetermination);
507

    
508
        if(setOfAll.size() == 0){
509
            // no need querying the data base
510
            return new ArrayList<T>();
511
        }
512

    
513
        String queryString =
514
            "SELECT sob " +
515
            " FROM SpecimenOrObservationBase sob" +
516
            " WHERE sob in (:setOfAll)";
517

    
518
        if(type != null && !type.equals(SpecimenOrObservationBase.class)){
519
            queryString += " AND sob.class = :type";
520
        }
521
        queryString += orderByClause("sob", orderHints);
522

    
523
        Query query = getSession().createQuery(queryString);
524
        query.setParameterList("setOfAll", setOfAll);
525

    
526
        if(type != null && !type.equals(SpecimenOrObservationBase.class)){
527
            query.setParameter("type", type.getSimpleName());
528
        }
529

    
530
        addLimitAndStart(query, limit, start);
531

    
532
        @SuppressWarnings("unchecked")
533
        List<T> results = query.list();
534
        defaultBeanInitializer.initializeAll(results, propertyPaths);
535
        return results;
536
    }
537

    
538
    private List<SpecimenNodeWrapper> querySpecimen(
539
            Query query, List<UUID> taxonNodeUuids,
540
            Integer limit, Integer start){
541
        query.setParameterList("taxonNodeUuids", taxonNodeUuids);
542

    
543
        addLimitAndStart(query, limit, start);
544

    
545
        List<SpecimenNodeWrapper> list = new ArrayList<>();
546
        @SuppressWarnings("unchecked")
547
        List<Object[]> result = query.list();
548
        for(Object[] object : result){
549
            list.add(new SpecimenNodeWrapper(
550
                    new UuidAndTitleCache<>(
551
                            (UUID) object[0],
552
                            (Integer) object[1],
553
                            (String) object[2]),
554
                    (TaxonNode)object[3]));
555
        }
556
        return list;
557
    }
558

    
559
    private List<SpecimenNodeWrapper> queryIndividualAssociatedSpecimen(List<UUID> taxonNodeUuids,
560
            Integer limit, Integer start){
561
        String queryString =  "SELECT "
562
                + "de.associatedSpecimenOrObservation.uuid, "
563
                + "de.associatedSpecimenOrObservation.id, "
564
                + "de.associatedSpecimenOrObservation.titleCache, "
565
                + "tn "
566
                + "FROM DescriptionElementBase AS de "
567
                + "LEFT JOIN de.inDescription AS d "
568
                + "LEFT JOIN d.taxon AS t "
569
                + "JOIN t.taxonNodes AS tn "
570
                + "WHERE d.class = 'TaxonDescription' "
571
                + "AND tn.uuid in (:taxonNodeUuids) "
572
                ;
573
        Query query = getSession().createQuery(queryString);
574
        return querySpecimen(query, taxonNodeUuids, limit, start);
575
    }
576

    
577
    private List<SpecimenNodeWrapper> queryTypeSpecimen(List<UUID> taxonNodeUuids,
578
            Integer limit, Integer start){
579
        String queryString =  "SELECT "
580
                + "td.typeSpecimen.uuid, "
581
                + "td.typeSpecimen.id, "
582
                + "td.typeSpecimen.titleCache, "
583
                + "tn "
584
                + "FROM SpecimenTypeDesignation AS td "
585
                + "LEFT JOIN td.typifiedNames AS tn "
586
                + "LEFT JOIN tn.taxonBases AS t "
587
                + "JOIN t.taxonNodes AS tn "
588
                + "WHERE tn.uuid in (:taxonNodeUuids) "
589
                ;
590
        Query query = getSession().createQuery(queryString);
591
        return querySpecimen(query, taxonNodeUuids, limit, start);
592
    }
593

    
594
    private List<SpecimenNodeWrapper> queryTaxonDeterminations(List<UUID> taxonNodeUuids,
595
            Integer limit, Integer start){
596
        String queryString =  "SELECT "
597
                + "det.identifiedUnit.uuid, "
598
                + "det.identifiedUnit.id, "
599
                + "det.identifiedUnit.titleCache, "
600
                + "tn "
601
                + "FROM DeterminationEvent AS det "
602
                + "LEFT JOIN det.taxon AS t "
603
                + "JOIN t.taxonNodes AS tn "
604
                + "WHERE tn.uuid in (:taxonNodeUuids) "
605
                ;
606
        Query query = getSession().createQuery(queryString);
607
        return querySpecimen(query, taxonNodeUuids, limit, start);
608
    }
609

    
610
    private List<SpecimenNodeWrapper> queryTaxonNameDeterminations(List<UUID> taxonNodeUuids,
611
            Integer limit, Integer start){
612
        String queryString =  "SELECT "
613
                + "det.identifiedUnit.uuid, "
614
                + "det.identifiedUnit.id, "
615
                + "det.identifiedUnit.titleCache, "
616
                + "tn "
617
                + "FROM DeterminationEvent AS det "
618
                + "LEFT JOIN det.taxonName AS n "
619
                + "LEFT JOIN n.taxonBases AS t "
620
                + "JOIN t.taxonNodes AS tn "
621
                + "WHERE tn.uuid in (:taxonNodeUuids) "
622
                ;
623
        Query query = getSession().createQuery(queryString);
624
        return querySpecimen(query, taxonNodeUuids, limit, start);
625
    }
626

    
627
    @Override
628
    public Collection<SpecimenNodeWrapper> listUuidAndTitleCacheByAssociatedTaxon(List<UUID> taxonNodeUuids,
629
            Integer limit, Integer start){
630

    
631
        Collection<SpecimenNodeWrapper> wrappers = new HashSet<>();
632
        wrappers.addAll(queryIndividualAssociatedSpecimen(taxonNodeUuids, limit, start));
633
        wrappers.addAll(queryTaxonDeterminations(taxonNodeUuids, limit, start));
634
        wrappers.addAll(queryTaxonNameDeterminations(taxonNodeUuids, limit, start));
635
        wrappers.addAll(queryTypeSpecimen(taxonNodeUuids, limit, start));
636

    
637
        return wrappers;
638
    }
639

    
640
    @Override
641
    public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> listUuidAndTitleCacheByAssociatedTaxon(Class<T> clazz, Taxon associatedTaxon,
642
            Integer limit, Integer start, List<OrderHint> orderHints){
643
        Query query = createSpecimenQuery("sob.uuid, sob.id, sob.titleCache", clazz, associatedTaxon, limit, start, orderHints, null);
644
        if(query==null){
645
            return Collections.emptyList();
646
        }
647
        List<UuidAndTitleCache<SpecimenOrObservationBase>> list = new ArrayList<>();
648
        @SuppressWarnings("unchecked")
649
        List<Object[]> result = query.list();
650
        for(Object[] object : result){
651
            list.add(new UuidAndTitleCache<>((UUID) object[0],(Integer) object[1], (String) object[2]));
652
        }
653
        return list;
654
    }
655

    
656
    @Override
657
    public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> clazz,
658
            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
659
        Query query = createSpecimenQuery("sob", clazz, associatedTaxon, limit, start, orderHints, propertyPaths);
660
        if(query==null){
661
            return Collections.emptyList();
662
        }
663
        @SuppressWarnings("unchecked")
664
        List<T> results = query.list();
665
        defaultBeanInitializer.initializeAll(results, propertyPaths);
666
        return results;
667
    }
668

    
669
    private <T extends SpecimenOrObservationBase> Query createSpecimenQuery(String select, Class<T> clazz,
670
            Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths){
671
        Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();
672
        Set<Integer> setOfAllIds = new HashSet<>();
673

    
674
        Criteria criteria = null;
675
        if(clazz == null) {
676
            criteria = getSession().createCriteria(type, "specimen");
677
        } else {
678
            criteria = getSession().createCriteria(clazz, "specimen");
679
        }
680

    
681
        Disjunction determinationOr = Restrictions.disjunction();
682

    
683
        // A Taxon may be referenced by the DeterminationEvent of the SpecimenOrObservationBase
684
        Criteria determinationsCriteria = criteria.createCriteria("determinations");
685

    
686
        determinationOr.add(Restrictions.eq("taxon", associatedTaxon));
687
        //check also for synonyms
688
        for (Synonym synonym : associatedTaxon.getSynonyms()) {
689
            determinationOr.add(Restrictions.eq("taxon", synonym));
690
        }
691

    
692
        //check also for name determinations
693
        determinationOr.add(Restrictions.eq("taxonName", associatedTaxon.getName()));
694
        for (TaxonName synonymName : associatedTaxon.getSynonymNames()) {
695
            determinationOr.add(Restrictions.eq("taxonName", synonymName));
696
        }
697

    
698
        determinationsCriteria.add(determinationOr);
699

    
700
        if(limit != null) {
701
            if(start != null) {
702
                criteria.setFirstResult(start);
703
            } else {
704
                criteria.setFirstResult(0);
705
            }
706
            criteria.setMaxResults(limit);
707
        }
708
        criteria.setProjection(Projections.property("id"));
709

    
710
        addOrder(criteria,orderHints);
711

    
712
        @SuppressWarnings("unchecked")
713
        List<Integer> detResults = criteria.list();
714
        setOfAllIds.addAll(detResults);
715

    
716
        // The IndividualsAssociation elements in a TaxonDescription contain DerivedUnits
717
        setOfAllIds.addAll(descriptionDao.getIndividualAssociationSpecimenIDs(
718
                associatedTaxon.getUuid(), null, null, 0, null));
719

    
720

    
721
        // SpecimenTypeDesignations may be associated with the TaxonName.
722
        setOfAllIds.addAll(taxonNameDao.getTypeSpecimenIdsForTaxonName(
723
                associatedTaxon.getName(), null, null, null));
724

    
725
        // SpecimenTypeDesignations may be associated with any HomotypicalGroup related to the specific Taxon.
726
        //TODO adapt to set of ids
727
        for(HomotypicalGroup homotypicalGroup :  associatedTaxon.getHomotypicSynonymyGroups()) {
728
            List<SpecimenTypeDesignation> byHomotypicalGroup = homotypicalGroupDao.getTypeDesignations(homotypicalGroup, SpecimenTypeDesignation.class, null, null, 0, null);
729
            for (SpecimenTypeDesignation specimenTypeDesignation : byHomotypicalGroup) {
730
                setOfAll.add(specimenTypeDesignation.getTypeSpecimen());
731
            }
732
        }
733

    
734
        if(setOfAllIds.size() == 0){
735
            // no need querying the data base
736
            return null;
737
        }
738

    
739
        String queryString =
740
            "select "+select+
741
            " from SpecimenOrObservationBase sob" +
742
            " where sob.id in (:setOfAllIds)";
743

    
744
        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
745
            queryString += " and sob.class = :type ";
746
        }
747

    
748
        if(orderHints != null && orderHints.size() > 0){
749
            queryString += " order by ";
750
            String orderStr = "";
751
            for(OrderHint orderHint : orderHints){
752
                if(orderStr.length() > 0){
753
                    orderStr += ", ";
754
                }
755
                queryString += "sob." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
756
            }
757
            queryString += orderStr;
758
        }
759

    
760
        Query query = getSession().createQuery(queryString);
761
        query.setParameterList("setOfAllIds", setOfAllIds);
762

    
763
        if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
764
            query.setParameter("type", clazz.getSimpleName());
765
        }
766

    
767
        addLimitAndStart(query, limit, start);
768

    
769
        return query;
770
    }
771

    
772
    @Override
773
    public Collection<SpecimenOrObservationBase> listBySpecimenOrObservationType(SpecimenOrObservationType type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
774
        String queryString = "FROM SpecimenOrObservationBase specimens "
775
                + " WHERE specimens.recordBasis = :type ";
776

    
777
        queryString += orderByClause("specimens", orderHints);
778

    
779
        Query query = getSession().createQuery(queryString);
780
        query.setParameter("type", type);
781

    
782
        addLimitAndStart(query, limit, start);
783

    
784
        @SuppressWarnings({ "unchecked", "rawtypes" })
785
        List<SpecimenOrObservationBase> results = query.list();
786
        defaultBeanInitializer.initializeAll(results, propertyPaths);
787
        return results;
788
    }
789

    
790

    
791
    @Override
792
    public Collection<DeterminationEvent> listDeterminationEvents(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
793
        String queryString = "FROM DeterminationEvent determination "
794
                + " WHERE determination.identifiedUnit = :specimen";
795

    
796
        queryString += orderByClause("determination", orderHints);
797

    
798
        Query query = getSession().createQuery(queryString);
799
        query.setParameter("specimen", specimen);
800

    
801
        addLimitAndStart(query, limit, start);
802

    
803
        @SuppressWarnings("unchecked")
804
        List<DeterminationEvent> results = query.list();
805
        defaultBeanInitializer.initializeAll(results, propertyPaths);
806
        return results;
807
    }
808

    
809
    @Override
810
    public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
811
        String queryString = "FROM SpecimenTypeDesignation designations "
812
                + " WHERE designations.typeSpecimen = :specimen";
813

    
814
        queryString += orderByClause("designations", orderHints);
815

    
816
        Query query = getSession().createQuery(queryString);
817
        query.setParameter("specimen", specimen);
818

    
819
        addLimitAndStart(query, limit, start);
820

    
821
        @SuppressWarnings("unchecked")
822
        List<SpecimenTypeDesignation> results = query.list();
823
        defaultBeanInitializer.initializeAll(results, propertyPaths);
824
        return results;
825
    }
826

    
827

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

    
833
        queryString += orderByClause("associations", orderHints);
834

    
835
        Query query = getSession().createQuery(queryString);
836
        query.setParameter("specimen", specimen);
837

    
838
        addLimitAndStart(query, limit, start);
839

    
840
        @SuppressWarnings("unchecked")
841
        List<IndividualsAssociation> results = query.list();
842
        defaultBeanInitializer.initializeAll(results, propertyPaths);
843
        return results;
844
    }
845

    
846
    @Override
847
    public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
848
        //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
849
        String queryString = "FROM DescriptionBase descriptions "
850
                + " WHERE descriptions.describedSpecimenOrObservation = :specimen";
851

    
852
        queryString += orderByClause("descriptions", orderHints);
853

    
854
        Query query = getSession().createQuery(queryString);
855
        query.setParameter("specimen", specimen);
856

    
857
        addLimitAndStart(query, limit, start);
858

    
859
        @SuppressWarnings("unchecked")
860
        List<DescriptionBase<?>> results = query.list();
861
        defaultBeanInitializer.initializeAll(results, propertyPaths);
862
        return results;
863
    }
864

    
865
    /**
866
     * {@inheritDoc}
867
     */
868
    @Override
869
    public List<FieldUnit> findFieldUnitsForGatheringEvent(UUID gatheringEventUuid, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
870
        String queryString = "FROM SpecimenOrObservationBase sob "
871
                + "WHERE sob.gatheringEvent.uuid = :gatheringEventUuid";
872

    
873
        queryString += orderByClause("sob", orderHints);
874

    
875
        Query query = getSession().createQuery(queryString);
876
        query.setParameter("gatheringEventUuid", gatheringEventUuid);
877

    
878
        addLimitAndStart(query, limit, start);
879

    
880
        @SuppressWarnings("unchecked")
881
        List<FieldUnit> results = query.list();
882
        defaultBeanInitializer.initializeAll(results, propertyPaths);
883
        return results;
884
    }
885

    
886
    /**
887
     *
888
     * {@inheritDoc}
889
     */
890
    @Override
891
    public List<DerivedUnit> findByGeneticAccessionNumber(String accessionNumberString, List<String> propertyPaths) {
892
        String queryString = "SELECT dnaSample FROM DnaSample dnaSample join dnaSample.sequences sequence WHERE sequence.geneticAccessionNumber LIKE :accessionNumberString";
893
        Query query = getSession().createQuery(queryString);
894
        query.setParameter("accessionNumberString", accessionNumberString);
895
        @SuppressWarnings("unchecked")
896
        List<DerivedUnit> dnaSamples = query.list();
897
        defaultBeanInitializer.initializeAll(dnaSamples, propertyPaths);
898
        List<DerivedUnit> results = new ArrayList<>();
899
        for (DerivedUnit sample:dnaSamples){
900
            extractDeterminedOriginals(sample, results);
901
        }
902

    
903
        return results;
904
    }
905

    
906
    /**
907
     * @param dnaSamples
908
     * @param results
909
     */
910
    private void extractDeterminedOriginals(DerivedUnit sample, List<DerivedUnit> results) {
911

    
912
        if (sample.getDeterminations() != null){
913
            results.add(sample);
914
        }else{
915
            extractDeterminedOriginals(sample, results);
916
        }
917
    }
918

    
919
    /**
920
     * {@inheritDoc}
921
     */
922
    @Override
923
    public List<SpecimenOrObservationBase> findOriginalsForDerivedUnit(UUID derivedUnitUuid, List<String> propertyPaths) {
924
        String queryString = "SELECT DISTINCT o FROM DerivedUnit du"
925
                + " JOIN du.derivedFrom.originals o WHERE du.uuid LIKE :derivedUnitUuid";
926
        Query query = getSession().createQuery(queryString);
927
        query.setParameter("derivedUnitUuid", derivedUnitUuid);
928
        @SuppressWarnings("unchecked")
929
        List<SpecimenOrObservationBase> results = query.list();
930
        defaultBeanInitializer.initializeAll(results, propertyPaths);
931
        return results;
932
    }
933

    
934
    /**
935
     * {@inheritDoc}
936
     */
937
    @Override
938
    public List<Point> findPointsForFieldUnitList(List<UUID> fieldUnitUuids) {
939
        String queryString = "SELECT DISTINCT fu.gatheringEvent.exactLocation FROM FieldUnit fu"
940
                + "  WHERE fu.uuid IN (:fieldUnitUuids)";
941
        Query query = getSession().createQuery(queryString);
942
        query.setParameterList("fieldUnitUuids", fieldUnitUuids);
943
        @SuppressWarnings("unchecked")
944
        List<Point> results = query.list();
945

    
946
        return results;
947
    }
948

    
949
}
(2-2/2)