ref #6241 replaced @created by @since in cdmlib
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / occurrence / OccurrenceDaoHibernateImpl.java
1 /**
2 * Copyright (C) 2008 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 */
6
7 package eu.etaxonomy.cdm.persistence.dao.hibernate.occurrence;
8
9 import java.util.ArrayList;
10 import java.util.Collection;
11 import java.util.Collections;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Set;
15 import java.util.UUID;
16
17 import org.apache.log4j.Logger;
18 import org.hibernate.Criteria;
19 import org.hibernate.Hibernate;
20 import org.hibernate.Query;
21 import org.hibernate.Session;
22 import org.hibernate.criterion.Disjunction;
23 import org.hibernate.criterion.ProjectionList;
24 import org.hibernate.criterion.Projections;
25 import org.hibernate.criterion.Restrictions;
26 import org.hibernate.envers.query.AuditEntity;
27 import org.hibernate.envers.query.AuditQuery;
28 import org.hibernate.search.FullTextSession;
29 import org.hibernate.search.Search;
30 import org.springframework.beans.factory.annotation.Autowired;
31 import org.springframework.stereotype.Repository;
32
33 import eu.etaxonomy.cdm.model.common.CdmBase;
34 import eu.etaxonomy.cdm.model.description.DescriptionBase;
35 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
36 import eu.etaxonomy.cdm.model.media.Media;
37 import eu.etaxonomy.cdm.model.molecular.DnaSample;
38 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
39 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
40 import eu.etaxonomy.cdm.model.name.TaxonName;
41 import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
42 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
43 import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
44 import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
45 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
46 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
47 import eu.etaxonomy.cdm.model.taxon.Synonym;
48 import eu.etaxonomy.cdm.model.taxon.Taxon;
49 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
50 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
51 import eu.etaxonomy.cdm.model.view.AuditEvent;
52 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
53 import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;
54 import eu.etaxonomy.cdm.persistence.dao.hibernate.taxon.TaxonDaoHibernateImpl;
55 import eu.etaxonomy.cdm.persistence.dao.name.IHomotypicalGroupDao;
56 import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
57 import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
58 import eu.etaxonomy.cdm.persistence.dto.SpecimenNodeWrapper;
59 import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
60 import eu.etaxonomy.cdm.persistence.query.MatchMode;
61 import eu.etaxonomy.cdm.persistence.query.OrderHint;
62
63 /**
64 * @author a.babadshanjan
65 * @since 01.09.2008
66 */
67 @Repository
68 public class OccurrenceDaoHibernateImpl extends IdentifiableDaoBase<SpecimenOrObservationBase> implements IOccurrenceDao {
69
70 @SuppressWarnings("unused")
71 private static final Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);
72
73 @Autowired
74 private IDescriptionDao descriptionDao;
75
76 @Autowired
77 private ITaxonNameDao taxonNameDao;
78
79 @Autowired
80 private IHomotypicalGroupDao homotypicalGroupDao;
81
82 public OccurrenceDaoHibernateImpl() {
83 super(SpecimenOrObservationBase.class);
84 indexedClasses = new Class[7];
85 indexedClasses[0] = FieldUnit.class;
86 indexedClasses[1] = DerivedUnit.class;
87 indexedClasses[5] = DnaSample.class;
88 }
89
90 @Override
91 public int countDerivationEvents(SpecimenOrObservationBase occurence) {
92 checkNotInPriorView("OccurrenceDaoHibernateImpl.countDerivationEvents(SpecimenOrObservationBase occurence)");
93 Query query = getSession().createQuery("select count(distinct derivationEvent) from DerivationEvent derivationEvent join derivationEvent.originals occurence where occurence = :occurence");
94 query.setParameter("occurence", occurence);
95
96 return ((Long)query.uniqueResult()).intValue();
97 }
98
99 @Override
100 public int countDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase) {
101 AuditEvent auditEvent = getAuditEventFromContext();
102 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
103 Criteria criteria = getSession().createCriteria(DeterminationEvent.class);
104 if(occurrence != null) {
105 criteria.add(Restrictions.eq("identifiedUnit",occurrence));
106 }
107
108 if(taxonBase != null) {
109 criteria.add(Restrictions.eq("taxon",taxonBase));
110 }
111
112 criteria.setProjection(Projections.rowCount());
113 return ((Number)criteria.uniqueResult()).intValue();
114 } else {
115 AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());
116
117 if(occurrence != null) {
118 query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));
119 }
120
121 if(taxonBase != null) {
122 query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));
123 }
124 query.addProjection(AuditEntity.id().count());
125
126 return ((Long)query.getSingleResult()).intValue();
127 }
128 }
129
130 @Override
131 public int countMedia(SpecimenOrObservationBase occurence) {
132 checkNotInPriorView("OccurrenceDaoHibernateImpl.countMedia(SpecimenOrObservationBase occurence)");
133 Query query = getSession().createQuery("select count(media) from SpecimenOrObservationBase occurence join occurence.media media where occurence = :occurence");
134 query.setParameter("occurence", occurence);
135
136 return ((Long)query.uniqueResult()).intValue();
137 }
138
139 @Override
140 public List<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {
141 checkNotInPriorView("OccurrenceDaoHibernateImpl.getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber)");
142 Query query = getSession().createQuery("select distinct derivationEvent from DerivationEvent derivationEvent join derivationEvent.originals occurence where occurence = :occurence");
143 query.setParameter("occurence", occurence);
144
145 if(pageSize != null) {
146 query.setMaxResults(pageSize);
147 if(pageNumber != null) {
148 query.setFirstResult(pageNumber * pageSize);
149 } else {
150 query.setFirstResult(0);
151 }
152 }
153
154 List<DerivationEvent> result = query.list();
155 defaultBeanInitializer.initializeAll(result, propertyPaths);
156 return result;
157 }
158
159 @Override
160 public List<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
161 AuditEvent auditEvent = getAuditEventFromContext();
162 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
163 Criteria criteria = getSession().createCriteria(DeterminationEvent.class);
164 if(occurrence != null) {
165 criteria.add(Restrictions.eq("identifiedUnit",occurrence));
166 }
167
168 if(taxonBase != null) {
169 criteria.add(Restrictions.eq("taxon",taxonBase));
170 }
171
172 if(pageSize != null) {
173 criteria.setMaxResults(pageSize);
174 if(pageNumber != null) {
175 criteria.setFirstResult(pageNumber * pageSize);
176 } else {
177 criteria.setFirstResult(0);
178 }
179 }
180 List<DeterminationEvent> result = criteria.list();
181 defaultBeanInitializer.initializeAll(result, propertyPaths);
182 return result;
183 } else {
184 AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(DeterminationEvent.class,auditEvent.getRevisionNumber());
185 if(occurrence != null) {
186 query.add(AuditEntity.relatedId("identifiedUnit").eq(occurrence.getId()));
187 }
188
189 if(taxonBase != null) {
190 query.add(AuditEntity.relatedId("taxon").eq(taxonBase.getId()));
191 }
192 if(pageSize != null) {
193 query.setMaxResults(pageSize);
194 if(pageNumber != null) {
195 query.setFirstResult(pageNumber * pageSize);
196 } else {
197 query.setFirstResult(0);
198 }
199 }
200 List<DeterminationEvent> result = query.getResultList();
201 defaultBeanInitializer.initializeAll(result, propertyPaths);
202 return result;
203 }
204 }
205
206 @Override
207 public List<Media> getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
208 checkNotInPriorView("OccurrenceDaoHibernateImpl.getMedia(SpecimenOrObservationBase occurence, Integer pageSize, Integer pageNumber, List<String> propertyPaths)");
209 Query query = getSession().createQuery("select media from SpecimenOrObservationBase occurence join occurence.media media where occurence = :occurence");
210 query.setParameter("occurence", occurence);
211
212 if(pageSize != null) {
213 query.setMaxResults(pageSize);
214 if(pageNumber != null) {
215 query.setFirstResult(pageNumber * pageSize);
216 } else {
217 query.setFirstResult(0);
218 }
219 }
220
221 List<Media> results = query.list();
222 defaultBeanInitializer.initializeAll(results, propertyPaths);
223 return results;
224 }
225
226 @Override
227 public void rebuildIndex() {
228 FullTextSession fullTextSession = Search.getFullTextSession(getSession());
229
230 for(SpecimenOrObservationBase<?> occurrence : list(null,null)) { // re-index all taxon base
231
232 for(DeterminationEvent determination : occurrence.getDeterminations()) {
233 Hibernate.initialize(determination.getActor());
234 Hibernate.initialize(determination.getTaxon());
235 }
236 Hibernate.initialize(occurrence.getDefinition());
237 if(occurrence instanceof DerivedUnit) {
238 DerivedUnit derivedUnit = (DerivedUnit) occurrence;
239 Hibernate.initialize(derivedUnit.getCollection());
240 if(derivedUnit.getCollection() != null) {
241 Hibernate.initialize(derivedUnit.getCollection().getSuperCollection());
242 Hibernate.initialize(derivedUnit.getCollection().getInstitute());
243 }
244 Hibernate.initialize(derivedUnit.getStoredUnder());
245 SpecimenOrObservationBase<?> original = derivedUnit.getOriginalUnit();
246 if(original != null && original.isInstanceOf(FieldUnit.class)) {
247 FieldUnit fieldUnit = CdmBase.deproxy(original, FieldUnit.class);
248 Hibernate.initialize(fieldUnit.getGatheringEvent());
249 if(fieldUnit.getGatheringEvent() != null) {
250 Hibernate.initialize(fieldUnit.getGatheringEvent().getActor());
251 }
252 }
253 }
254 fullTextSession.index(occurrence);
255 }
256 fullTextSession.flushToIndexes();
257 }
258
259 @Override
260 public int count(Class<? extends SpecimenOrObservationBase> clazz, TaxonName determinedAs) {
261
262 Criteria criteria = null;
263 if(clazz == null) {
264 criteria = getSession().createCriteria(type);
265 } else {
266 criteria = getSession().createCriteria(clazz);
267 }
268
269 criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));
270 criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
271 return ((Number)criteria.uniqueResult()).intValue();
272 }
273
274 @Override
275 public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonName determinedAs, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
276 Criteria criteria = null;
277 if(clazz == null) {
278 criteria = getSession().createCriteria(type);
279 } else {
280 criteria = getSession().createCriteria(clazz);
281 }
282
283 criteria.createCriteria("determinations").add(Restrictions.eq("taxonName", determinedAs));
284
285 if(limit != null) {
286 if(start != null) {
287 criteria.setFirstResult(start);
288 } else {
289 criteria.setFirstResult(0);
290 }
291 criteria.setMaxResults(limit);
292 }
293
294 addOrder(criteria,orderHints);
295
296 @SuppressWarnings("unchecked")
297 List<SpecimenOrObservationBase> results = criteria.list();
298 defaultBeanInitializer.initializeAll(results, propertyPaths);
299 return results;
300 }
301
302 @Override
303 public int count(Class<? extends SpecimenOrObservationBase> clazz, TaxonBase determinedAs) {
304
305 Criteria criteria = null;
306 if(clazz == null) {
307 criteria = getSession().createCriteria(type);
308 } else {
309 criteria = getSession().createCriteria(clazz);
310 }
311
312 criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));
313 criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
314 return ((Number)criteria.uniqueResult()).intValue();
315 }
316
317 @Override
318 public List<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> clazz, TaxonBase determinedAs, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
319 Criteria criteria = null;
320 if(clazz == null) {
321 criteria = getSession().createCriteria(type);
322 } else {
323 criteria = getSession().createCriteria(clazz);
324 }
325
326 criteria.createCriteria("determinations").add(Restrictions.eq("taxon", determinedAs));
327
328 if(limit != null) {
329 if(start != null) {
330 criteria.setFirstResult(start);
331 } else {
332 criteria.setFirstResult(0);
333 }
334 criteria.setMaxResults(limit);
335 }
336
337 addOrder(criteria,orderHints);
338
339 @SuppressWarnings("unchecked")
340 List<SpecimenOrObservationBase> results = criteria.list();
341 defaultBeanInitializer.initializeAll(results, propertyPaths);
342 return results;
343 }
344
345 @Override
346 public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> findOccurrencesUuidAndTitleCache(
347 Class<T> clazz, String queryString, String significantIdentifier, SpecimenOrObservationType recordBasis,
348 Taxon associatedTaxon, TaxonName associatedTaxonName, MatchMode matchmode, Integer limit, Integer start,
349 List<OrderHint> orderHints) {
350 Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
351 associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, null);
352 if(criteria!=null){
353 ProjectionList projectionList = Projections.projectionList();
354 projectionList.add(Projections.property("uuid"));
355 projectionList.add(Projections.property("id"));
356 projectionList.add(Projections.property("titleCache"));
357 criteria.setProjection(projectionList);
358
359 List<Object[]> result = criteria.list();
360 List<UuidAndTitleCache<SpecimenOrObservationBase>> uuidAndTitleCacheList = new ArrayList<>();
361 for(Object[] object : result){
362 uuidAndTitleCacheList.add(new UuidAndTitleCache<SpecimenOrObservationBase>((UUID) object[0],(Integer) object[1], (String) object[2]));
363 }
364 return uuidAndTitleCacheList;
365 }
366 return Collections.emptyList();
367 }
368
369 @Override
370 public <T extends SpecimenOrObservationBase> List<T> findOccurrences(Class<T> clazz, String queryString,
371 String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,
372 MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
373
374 Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
375 associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);
376 if(criteria!=null){
377 @SuppressWarnings("unchecked")
378 List<T> results = criteria.list();
379 defaultBeanInitializer.initializeAll(results, propertyPaths);
380 return results;
381 }
382 return Collections.emptyList();
383 }
384
385 private <T extends SpecimenOrObservationBase> Criteria createFindOccurrenceCriteria(Class<T> clazz, String queryString,
386 String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName, MatchMode matchmode, Integer limit,
387 Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
388 Criteria criteria = null;
389
390 if(clazz == null) {
391 criteria = getSession().createCriteria(type);
392 } else {
393 criteria = getSession().createCriteria(clazz);
394 }
395
396 //queryString
397 if (queryString != null) {
398 if(matchmode == null) {
399 matchmode = MatchMode.ANYWHERE;
400 criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString)));
401 } else if(matchmode == MatchMode.BEGINNING) {
402 criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.START));
403 } else if(matchmode == MatchMode.END) {
404 criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.END));
405 } else if(matchmode == MatchMode.EXACT) {
406 criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.EXACT));
407 } else {
408 criteria.add(Restrictions.ilike("titleCache", matchmode.queryStringFrom(queryString), org.hibernate.criterion.MatchMode.ANYWHERE));
409 }
410 }
411
412 //significant identifier
413 if (significantIdentifier != null) {
414 criteria.add(Restrictions.or(Restrictions.ilike("accessionNumber", significantIdentifier),
415 Restrictions.ilike("catalogNumber", significantIdentifier), Restrictions.ilike("barcode", significantIdentifier)));
416 }
417
418 //recordBasis/SpecimenOrObservationType
419 Set<SpecimenOrObservationType> typeAndSubtypes = new HashSet<SpecimenOrObservationType>();
420 if(recordBasis==null){
421 //add all types
422 SpecimenOrObservationType[] values = SpecimenOrObservationType.values();
423 for (SpecimenOrObservationType specimenOrObservationType : values) {
424 typeAndSubtypes.add(specimenOrObservationType);
425 }
426 }
427 else{
428 typeAndSubtypes = recordBasis.getGeneralizationOf(true);
429 typeAndSubtypes.add(recordBasis);
430 }
431 criteria.add(Restrictions.in("recordBasis", typeAndSubtypes));
432
433 Set<UUID> associationUuids = new HashSet<UUID>();
434 //taxon associations
435 if(associatedTaxon!=null){
436 List<UuidAndTitleCache<SpecimenOrObservationBase>> associatedTaxaList = listUuidAndTitleCacheByAssociatedTaxon(clazz, associatedTaxon, limit, start, orderHints);
437 if(associatedTaxaList!=null){
438 for (UuidAndTitleCache<SpecimenOrObservationBase> uuidAndTitleCache : associatedTaxaList) {
439 associationUuids.add(uuidAndTitleCache.getUuid());
440 }
441 }
442 }
443 //taxon name associations
444 else if(associatedTaxonName!=null){
445 List<? extends SpecimenOrObservationBase> associatedTaxaList = listByAssociatedTaxonName(clazz, associatedTaxonName, limit, start, orderHints, propertyPaths);
446 if(associatedTaxaList!=null){
447 for (SpecimenOrObservationBase specimenOrObservationBase : associatedTaxaList) {
448 associationUuids.add(specimenOrObservationBase.getUuid());
449 }
450 }
451 }
452 if(associatedTaxon!=null || associatedTaxonName!=null){
453 if(!associationUuids.isEmpty()){
454 criteria.add(Restrictions.in("uuid", associationUuids));
455 }
456 else{
457 return null;
458 }
459 }
460 if(limit != null) {
461 if(start != null) {
462 criteria.setFirstResult(start);
463 } else {
464 criteria.setFirstResult(0);
465 }
466 criteria.setMaxResults(limit);
467 }
468
469 if(orderHints!=null){
470 addOrder(criteria,orderHints);
471 }
472 return criteria;
473 }
474
475
476 @Override
477 public <T extends SpecimenOrObservationBase> int countOccurrences(Class<T> clazz, String queryString,
478 String significantIdentifier, SpecimenOrObservationType recordBasis, Taxon associatedTaxon, TaxonName associatedTaxonName,
479 MatchMode matchmode, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
480 Criteria criteria = createFindOccurrenceCriteria(clazz, queryString, significantIdentifier, recordBasis,
481 associatedTaxon, associatedTaxonName, matchmode, limit, start, orderHints, propertyPaths);
482
483 if(criteria!=null){
484
485 criteria.setProjection(Projections.rowCount());
486
487 return ((Number)criteria.uniqueResult()).intValue();
488 }
489 return 0;
490 }
491
492 @Override
493 public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache(Integer limit, String pattern) {
494 List<UuidAndTitleCache<DerivedUnit>> list = new ArrayList<UuidAndTitleCache<DerivedUnit>>();
495 Session session = getSession();
496 Query query;
497 if (pattern != null){
498 query = session.createQuery("select uuid, id, titleCache from " + type.getSimpleName() + " where NOT dtype = " + FieldUnit.class.getSimpleName() +" AND titleCache like :pattern");
499 pattern = pattern.replace("*", "%");
500 pattern = pattern.replace("?", "_");
501 pattern = pattern + "%";
502 query.setParameter("pattern", pattern);
503 } else {
504 query = session.createQuery("select uuid, id, titleCache from " + type.getSimpleName() +" where NOT dtype = " + FieldUnit.class.getSimpleName());
505 }
506 if (limit != null){
507 query.setMaxResults(limit);
508 }
509
510
511
512 List<Object[]> result = query.list();
513
514 for(Object[] object : result){
515 list.add(new UuidAndTitleCache<DerivedUnit>(DerivedUnit.class, (UUID) object[0], (Integer)object[1], (String) object[2]));
516 }
517
518 return list;
519 }
520
521 @Override
522 public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
523 List<UuidAndTitleCache<FieldUnit>> list = new ArrayList<UuidAndTitleCache<FieldUnit>>();
524 Session session = getSession();
525
526 Query query = session.createQuery("select uuid, id, titleCache from " + type.getSimpleName() + " where dtype = " + FieldUnit.class.getSimpleName());
527
528 List<Object[]> result = query.list();
529
530 for(Object[] object : result){
531 list.add(new UuidAndTitleCache<FieldUnit>(FieldUnit.class, (UUID) object[0], (Integer)object[1], (String) object[2]));
532 }
533
534 return list;
535 }
536
537 @Override
538 public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxonName(Class<T> type,
539 TaxonName associatedTaxonName, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
540 Set<SpecimenOrObservationBase> setOfAll = new HashSet<SpecimenOrObservationBase>();
541
542 // A Taxon name may be referenced by the DeterminationEvent of the SpecimenOrObservationBase
543 List<SpecimenOrObservationBase> byDetermination = list(type, associatedTaxonName, null, 0, null, null);
544 setOfAll.addAll(byDetermination);
545
546 if(setOfAll.size() == 0){
547 // no need querying the data base
548 return new ArrayList<T>();
549 }
550
551 String queryString =
552 "select sob " +
553 " from SpecimenOrObservationBase sob" +
554 " where sob in (:setOfAll)";
555
556 if(type != null && !type.equals(SpecimenOrObservationBase.class)){
557 queryString += " and sob.class = :type";
558 }
559
560 if(orderHints != null && orderHints.size() > 0){
561 queryString += " order by ";
562 String orderStr = "";
563 for(OrderHint orderHint : orderHints){
564 if(orderStr.length() > 0){
565 orderStr += ", ";
566 }
567 queryString += "sob." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
568 }
569 queryString += orderStr;
570 }
571
572 Query query = getSession().createQuery(queryString);
573 query.setParameterList("setOfAll", setOfAll);
574
575 if(type != null && !type.equals(SpecimenOrObservationBase.class)){
576 query.setParameter("type", type.getSimpleName());
577 }
578
579 if(limit != null) {
580 if(start != null) {
581 query.setFirstResult(start);
582 } else {
583 query.setFirstResult(0);
584 }
585 query.setMaxResults(limit);
586 }
587
588
589 List<T> results = query.list();
590 defaultBeanInitializer.initializeAll(results, propertyPaths);
591 return results;
592 }
593
594 private List<SpecimenNodeWrapper> querySpecimen(
595 Query query, List<UUID> taxonNodeUuids,
596 Integer limit, Integer start){
597 query.setParameterList("taxonNodeUuids", taxonNodeUuids);
598
599 if(limit != null) {
600 if(start != null) {
601 query.setFirstResult(start);
602 } else {
603 query.setFirstResult(0);
604 }
605 query.setMaxResults(limit);
606 }
607
608 List<SpecimenNodeWrapper> list = new ArrayList<>();
609 List<Object[]> result = query.list();
610 for(Object[] object : result){
611 list.add(new SpecimenNodeWrapper(
612 new UuidAndTitleCache<SpecimenOrObservationBase>(
613 (UUID) object[0],
614 (Integer) object[1],
615 (String) object[2]),
616 (TaxonNode)object[3]));
617 }
618 return list;
619 }
620
621 private List<SpecimenNodeWrapper> queryIndividualAssociatedSpecimen(List<UUID> taxonNodeUuids,
622 Integer limit, Integer start){
623 String queryString = "SELECT "
624 + "de.associatedSpecimenOrObservation.uuid, "
625 + "de.associatedSpecimenOrObservation.id, "
626 + "de.associatedSpecimenOrObservation.titleCache, "
627 + "tn "
628 + "FROM DescriptionElementBase AS de "
629 + "LEFT JOIN de.inDescription AS d "
630 + "LEFT JOIN d.taxon AS t "
631 + "JOIN t.taxonNodes AS tn "
632 + "WHERE d.class = 'TaxonDescription' "
633 + "AND tn.uuid in (:taxonNodeUuids) "
634 ;
635 Query query = getSession().createQuery(queryString);
636 return querySpecimen(query, taxonNodeUuids, limit, start);
637 }
638
639 private List<SpecimenNodeWrapper> queryTypeSpecimen(List<UUID> taxonNodeUuids,
640 Integer limit, Integer start){
641 String queryString = "SELECT "
642 + "td.typeSpecimen.uuid, "
643 + "td.typeSpecimen.id, "
644 + "td.typeSpecimen.titleCache, "
645 + "tn "
646 + "FROM SpecimenTypeDesignation AS td "
647 + "LEFT JOIN td.typifiedNames AS tn "
648 + "LEFT JOIN tn.taxonBases AS t "
649 + "JOIN t.taxonNodes AS tn "
650 + "WHERE tn.uuid in (:taxonNodeUuids) "
651 ;
652 Query query = getSession().createQuery(queryString);
653 return querySpecimen(query, taxonNodeUuids, limit, start);
654 }
655
656 private List<SpecimenNodeWrapper> queryTaxonDeterminations(List<UUID> taxonNodeUuids,
657 Integer limit, Integer start){
658 String queryString = "SELECT "
659 + "det.identifiedUnit.uuid, "
660 + "det.identifiedUnit.id, "
661 + "det.identifiedUnit.titleCache, "
662 + "tn "
663 + "FROM DeterminationEvent AS det "
664 + "LEFT JOIN det.taxon AS t "
665 + "JOIN t.taxonNodes AS tn "
666 + "WHERE tn.uuid in (:taxonNodeUuids) "
667 ;
668 Query query = getSession().createQuery(queryString);
669 return querySpecimen(query, taxonNodeUuids, limit, start);
670 }
671
672 private List<SpecimenNodeWrapper> queryTaxonNameDeterminations(List<UUID> taxonNodeUuids,
673 Integer limit, Integer start){
674 String queryString = "SELECT "
675 + "det.identifiedUnit.uuid, "
676 + "det.identifiedUnit.id, "
677 + "det.identifiedUnit.titleCache, "
678 + "tn "
679 + "FROM DeterminationEvent AS det "
680 + "LEFT JOIN det.taxonName AS n "
681 + "LEFT JOIN n.taxonBases AS t "
682 + "JOIN t.taxonNodes AS tn "
683 + "WHERE tn.uuid in (:taxonNodeUuids) "
684 ;
685 Query query = getSession().createQuery(queryString);
686 return querySpecimen(query, taxonNodeUuids, limit, start);
687 }
688
689 @Override
690 public Collection<SpecimenNodeWrapper> listUuidAndTitleCacheByAssociatedTaxon(List<UUID> taxonNodeUuids,
691 Integer limit, Integer start){
692
693 Collection<SpecimenNodeWrapper> wrappers = new HashSet<>();
694 wrappers.addAll(queryIndividualAssociatedSpecimen(taxonNodeUuids, limit, start));
695 wrappers.addAll(queryTaxonDeterminations(taxonNodeUuids, limit, start));
696 wrappers.addAll(queryTaxonNameDeterminations(taxonNodeUuids, limit, start));
697 wrappers.addAll(queryTypeSpecimen(taxonNodeUuids, limit, start));
698
699 return wrappers;
700 }
701
702 @Override
703 public <T extends SpecimenOrObservationBase> List<UuidAndTitleCache<SpecimenOrObservationBase>> listUuidAndTitleCacheByAssociatedTaxon(Class<T> clazz, Taxon associatedTaxon,
704 Integer limit, Integer start, List<OrderHint> orderHints){
705 Query query = createSpecimenQuery("sob.uuid, sob.id, sob.titleCache", clazz, associatedTaxon, limit, start, orderHints, null);
706 if(query==null){
707 return Collections.emptyList();
708 }
709 List<UuidAndTitleCache<SpecimenOrObservationBase>> list = new ArrayList<>();
710 List<Object[]> result = query.list();
711 for(Object[] object : result){
712 list.add(new UuidAndTitleCache<SpecimenOrObservationBase>((UUID) object[0],(Integer) object[1], (String) object[2]));
713 }
714 return list;
715 }
716
717 @Override
718 public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> clazz,
719 Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
720 Query query = createSpecimenQuery("sob", clazz, associatedTaxon, limit, start, orderHints, propertyPaths);
721 if(query==null){
722 return Collections.emptyList();
723 }
724 List<T> results = query.list();
725 defaultBeanInitializer.initializeAll(results, propertyPaths);
726 return results;
727 }
728
729 private <T extends SpecimenOrObservationBase> Query createSpecimenQuery(String select, Class<T> clazz,
730 Taxon associatedTaxon, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths){
731 Set<SpecimenOrObservationBase> setOfAll = new HashSet<>();
732 Set<Integer> setOfAllIds = new HashSet<>();
733
734 Criteria criteria = null;
735 if(clazz == null) {
736 criteria = getSession().createCriteria(type, "specimen");
737 } else {
738 criteria = getSession().createCriteria(clazz, "specimen");
739 }
740
741 Disjunction determinationOr = Restrictions.disjunction();
742
743 // A Taxon may be referenced by the DeterminationEvent of the SpecimenOrObservationBase
744 Criteria determinationsCriteria = criteria.createCriteria("determinations");
745
746 determinationOr.add(Restrictions.eq("taxon", associatedTaxon));
747 //check also for synonyms
748 for (Synonym synonym : associatedTaxon.getSynonyms()) {
749 determinationOr.add(Restrictions.eq("taxon", synonym));
750 }
751
752 //check also for name determinations
753 determinationOr.add(Restrictions.eq("taxonName", associatedTaxon.getName()));
754 for (TaxonName synonymName : associatedTaxon.getSynonymNames()) {
755 determinationOr.add(Restrictions.eq("taxonName", synonymName));
756 }
757
758 determinationsCriteria.add(determinationOr);
759
760 if(limit != null) {
761 if(start != null) {
762 criteria.setFirstResult(start);
763 } else {
764 criteria.setFirstResult(0);
765 }
766 criteria.setMaxResults(limit);
767 }
768 criteria.setProjection(Projections.property("id"));
769
770 addOrder(criteria,orderHints);
771
772 @SuppressWarnings("unchecked")
773 List<Integer> detResults = criteria.list();
774 setOfAllIds.addAll(detResults);
775
776 // The IndividualsAssociation elements in a TaxonDescription contain DerivedUnits
777 setOfAllIds.addAll(descriptionDao.getIndividualAssociationSpecimenIDs(
778 associatedTaxon.getUuid(), null, null, 0, null));
779
780
781 // SpecimenTypeDesignations may be associated with the TaxonName.
782 setOfAllIds.addAll(taxonNameDao.getTypeSpecimenIdsForTaxonName(
783 associatedTaxon.getName(), null, null, null));
784
785 // SpecimenTypeDesignations may be associated with any HomotypicalGroup related to the specific Taxon.
786 //TODO adapt to set of ids
787 for(HomotypicalGroup homotypicalGroup : associatedTaxon.getHomotypicSynonymyGroups()) {
788 List<SpecimenTypeDesignation> byHomotypicalGroup = homotypicalGroupDao.getTypeDesignations(homotypicalGroup, SpecimenTypeDesignation.class, null, null, 0, null);
789 for (SpecimenTypeDesignation specimenTypeDesignation : byHomotypicalGroup) {
790 setOfAll.add(specimenTypeDesignation.getTypeSpecimen());
791 }
792 }
793
794 if(setOfAllIds.size() == 0){
795 // no need querying the data base
796 return null;
797 }
798
799 String queryString =
800 "select "+select+
801 " from SpecimenOrObservationBase sob" +
802 " where sob.id in (:setOfAllIds)";
803
804 if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
805 queryString += " and sob.class = :type ";
806 }
807
808 if(orderHints != null && orderHints.size() > 0){
809 queryString += " order by ";
810 String orderStr = "";
811 for(OrderHint orderHint : orderHints){
812 if(orderStr.length() > 0){
813 orderStr += ", ";
814 }
815 queryString += "sob." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
816 }
817 queryString += orderStr;
818 }
819
820 Query query = getSession().createQuery(queryString);
821 query.setParameterList("setOfAllIds", setOfAllIds);
822
823 if(clazz != null && !clazz.equals(SpecimenOrObservationBase.class)){
824 query.setParameter("type", clazz.getSimpleName());
825 }
826
827 if(limit != null) {
828 if(start != null) {
829 query.setFirstResult(start);
830 } else {
831 query.setFirstResult(0);
832 }
833 query.setMaxResults(limit);
834 }
835
836 return query;
837 }
838
839 @Override
840 public Collection<SpecimenOrObservationBase> listBySpecimenOrObservationType(SpecimenOrObservationType type, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
841 String queryString = "FROM SpecimenOrObservationBase specimens WHERE specimens.recordBasis = :type";
842
843 if(orderHints != null && orderHints.size() > 0){
844 queryString += " order by ";
845 String orderStr = "";
846 for(OrderHint orderHint : orderHints){
847 if(orderStr.length() > 0){
848 orderStr += ", ";
849 }
850 queryString += "specimens." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
851 }
852 queryString += orderStr;
853 }
854
855 Query query = getSession().createQuery(queryString);
856 query.setParameter("type", type);
857
858 if(limit != null) {
859 if(start != null) {
860 query.setFirstResult(start);
861 } else {
862 query.setFirstResult(0);
863 }
864 query.setMaxResults(limit);
865 }
866
867 List results = query.list();
868 defaultBeanInitializer.initializeAll(results, propertyPaths);
869 return results;
870 }
871
872 @Override
873 public Collection<DeterminationEvent> listDeterminationEvents(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
874 String queryString = "FROM DeterminationEvent determination WHERE determination.identifiedUnit = :specimen";
875
876 if(orderHints != null && orderHints.size() > 0){
877 queryString += " order by ";
878 String orderStr = "";
879 for(OrderHint orderHint : orderHints){
880 if(orderStr.length() > 0){
881 orderStr += ", ";
882 }
883 queryString += "determination." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
884 }
885 queryString += orderStr;
886 }
887
888 Query query = getSession().createQuery(queryString);
889 query.setParameter("specimen", specimen);
890
891 if(limit != null) {
892 if(start != null) {
893 query.setFirstResult(start);
894 } else {
895 query.setFirstResult(0);
896 }
897 query.setMaxResults(limit);
898 }
899
900 List results = query.list();
901 defaultBeanInitializer.initializeAll(results, propertyPaths);
902 return results;
903 }
904
905 @Override
906 public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
907 String queryString = "FROM SpecimenTypeDesignation designations WHERE designations.typeSpecimen = :specimen";
908
909 if(orderHints != null && orderHints.size() > 0){
910 queryString += " ORDER BY ";
911 String orderStr = "";
912 for(OrderHint orderHint : orderHints){
913 if(orderStr.length() > 0){
914 orderStr += ", ";
915 }
916 queryString += "designations." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
917 }
918 queryString += orderStr;
919 }
920
921 Query query = getSession().createQuery(queryString);
922 query.setParameter("specimen", specimen);
923
924 if(limit != null) {
925 if(start != null) {
926 query.setFirstResult(start);
927 } else {
928 query.setFirstResult(0);
929 }
930 query.setMaxResults(limit);
931 }
932
933 @SuppressWarnings("unchecked")
934 List<SpecimenTypeDesignation> results = query.list();
935 defaultBeanInitializer.initializeAll(results, propertyPaths);
936 return results;
937 }
938
939 @Override
940 public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
941 //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
942 String queryString = "FROM IndividualsAssociation associations WHERE associations.associatedSpecimenOrObservation = :specimen";
943
944 if(orderHints != null && orderHints.size() > 0){
945 queryString += " order by ";
946 String orderStr = "";
947 for(OrderHint orderHint : orderHints){
948 if(orderStr.length() > 0){
949 orderStr += ", ";
950 }
951 queryString += "associations." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
952 }
953 queryString += orderStr;
954 }
955
956 Query query = getSession().createQuery(queryString);
957 query.setParameter("specimen", specimen);
958
959 if(limit != null) {
960 if(start != null) {
961 query.setFirstResult(start);
962 } else {
963 query.setFirstResult(0);
964 }
965 query.setMaxResults(limit);
966 }
967
968 List results = query.list();
969 defaultBeanInitializer.initializeAll(results, propertyPaths);
970 return results;
971 }
972
973 @Override
974 public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
975 //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
976 String queryString = "FROM DescriptionBase descriptions WHERE descriptions.describedSpecimenOrObservation = :specimen";
977
978 if(orderHints != null && orderHints.size() > 0){
979 queryString += " order by ";
980 String orderStr = "";
981 for(OrderHint orderHint : orderHints){
982 if(orderStr.length() > 0){
983 orderStr += ", ";
984 }
985 queryString += "descriptions." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
986 }
987 queryString += orderStr;
988 }
989
990 Query query = getSession().createQuery(queryString);
991 query.setParameter("specimen", specimen);
992
993 if(limit != null) {
994 if(start != null) {
995 query.setFirstResult(start);
996 } else {
997 query.setFirstResult(0);
998 }
999 query.setMaxResults(limit);
1000 }
1001
1002 List results = query.list();
1003 defaultBeanInitializer.initializeAll(results, propertyPaths);
1004 return results;
1005 }
1006
1007 /**
1008 * {@inheritDoc}
1009 */
1010 @Override
1011 public List<FieldUnit> getFieldUnitsForGatheringEvent(UUID gatheringEventUuid, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
1012 String queryString = "FROM SpecimenOrObservationBase s WHERE s.gatheringEvent.uuid = :gatheringEventUuid";
1013
1014 if(orderHints != null && orderHints.size() > 0){
1015 queryString += " order by ";
1016 String orderStr = "";
1017 for(OrderHint orderHint : orderHints){
1018 if(orderStr.length() > 0){
1019 orderStr += ", ";
1020 }
1021 queryString += "descriptions." + orderHint.getPropertyName() + " " + orderHint.getSortOrder().toHql();
1022 }
1023 queryString += orderStr;
1024 }
1025
1026 Query query = getSession().createQuery(queryString);
1027 query.setParameter("gatheringEventUuid", gatheringEventUuid);
1028
1029 if(limit != null) {
1030 if(start != null) {
1031 query.setFirstResult(start);
1032 } else {
1033 query.setFirstResult(0);
1034 }
1035 query.setMaxResults(limit);
1036 }
1037
1038 List results = query.list();
1039 defaultBeanInitializer.initializeAll(results, propertyPaths);
1040 return results;
1041 }
1042
1043 }