240b14104db2074e37d6fbba84958bd879d7b0d5
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / persistence / dao / hibernate / description / DescriptionDaoImpl.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.persistence.dao.hibernate.description;
11
12 import java.util.ArrayList;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.UUID;
18
19 import org.apache.commons.lang.ArrayUtils;
20 import org.apache.logging.log4j.LogManager;
21 import org.apache.logging.log4j.Logger;
22 import org.hibernate.Criteria;
23 import org.hibernate.criterion.Criterion;
24 import org.hibernate.criterion.ProjectionList;
25 import org.hibernate.criterion.Projections;
26 import org.hibernate.criterion.Restrictions;
27 import org.hibernate.envers.query.AuditEntity;
28 import org.hibernate.envers.query.AuditQuery;
29 import org.hibernate.query.Query;
30 import org.springframework.beans.factory.annotation.Qualifier;
31 import org.springframework.stereotype.Repository;
32
33 import eu.etaxonomy.cdm.model.common.LSID;
34 import eu.etaxonomy.cdm.model.common.MarkerType;
35 import eu.etaxonomy.cdm.model.description.CommonTaxonName;
36 import eu.etaxonomy.cdm.model.description.DescriptionBase;
37 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
38 import eu.etaxonomy.cdm.model.description.DescriptionType;
39 import eu.etaxonomy.cdm.model.description.Feature;
40 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
41 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
42 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
43 import eu.etaxonomy.cdm.model.description.TaxonDescription;
44 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
45 import eu.etaxonomy.cdm.model.location.NamedArea;
46 import eu.etaxonomy.cdm.model.media.Media;
47 import eu.etaxonomy.cdm.model.name.TaxonName;
48 import eu.etaxonomy.cdm.model.taxon.Taxon;
49 import eu.etaxonomy.cdm.model.term.DefinedTerm;
50 import eu.etaxonomy.cdm.model.view.AuditEvent;
51 import eu.etaxonomy.cdm.persistence.dao.common.OperationNotSupportedInPriorViewException;
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.dto.SortableTaxonNodeQueryResult;
55 import eu.etaxonomy.cdm.persistence.dto.TermDto;
56 import eu.etaxonomy.cdm.persistence.query.MatchMode;
57 import eu.etaxonomy.cdm.persistence.query.OrderHint;
58
59 @Repository
60 @Qualifier("descriptionDaoImpl")
61 public class DescriptionDaoImpl
62 extends IdentifiableDaoBase<DescriptionBase>
63 implements IDescriptionDao{
64
65 private static final Logger logger = LogManager.getLogger(DescriptionDaoImpl.class);
66
67 public DescriptionDaoImpl() {
68 super(DescriptionBase.class);
69 indexedClasses = new Class[3];
70 indexedClasses[0] = TaxonDescription.class;
71 indexedClasses[1] = TaxonNameDescription.class;
72 indexedClasses[2] = SpecimenDescription.class;
73 }
74
75 // @Override //Override for testing
76 // public DescriptionBase load(UUID uuid, List<String> propertyPaths){
77 // DescriptionBase bean = findByUuid(uuid);
78 // if(bean == null){
79 // return bean;
80 // }
81 // defaultBeanInitializer.initialize(bean, propertyPaths);
82 //
83 // return bean;
84 // }
85
86 @Override
87 public long countDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm status) {
88 checkNotInPriorView("DescriptionDaoImpl.countDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTermBase status)");
89 Query<Long> query = null;
90
91 if(status == null) {
92 query = getSession().createQuery("select count(distinct description) from TaxonDescription description left join description.descriptionElements element join element.area area where area in (:namedAreas)", Long.class);
93 } else {
94 query = getSession().createQuery("select count(distinct description) from TaxonDescription description left join description.descriptionElements element join element.area area join element.status status where area in (:namedAreas) and status = :status", Long.class);
95 query.setParameter("status", status);
96 }
97 query.setParameterList("namedAreas", namedAreas);
98
99 return query.uniqueResult();
100 }
101
102 @Override
103 public <T extends DescriptionElementBase> long countDescriptionElements(DescriptionBase description, Set<Feature> features, Class<T> clazz) {
104 return countDescriptionElements(description, null, features, clazz);
105 }
106
107 @Override
108 public <T extends DescriptionElementBase> long countDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
109 Set<Feature> features, Class<T> clazz) {
110 AuditEvent auditEvent = getAuditEventFromContext();
111 if (clazz == null){
112 clazz = (Class<T>)DescriptionElementBase.class;
113 }
114 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
115 Criteria criteria = getCriteria(clazz);
116
117 if(description != null) {
118 criteria.add(Restrictions.eq("inDescription", description));
119 }
120
121 if(descriptionType != null) {
122 criteria.createAlias("inDescription", "d").add(Restrictions.eq("d.class", descriptionType));
123 }
124
125 if(features != null && !features.isEmpty()) {
126 criteria.add(Restrictions.in("feature", features));
127 }
128
129 criteria.setProjection(Projections.rowCount());
130
131 return (Long)criteria.uniqueResult();
132 } else {
133 if(features != null && !features.isEmpty()) {
134 long count = 0;
135 for(Feature f : features) {
136 AuditQuery query = null;
137 query = makeAuditQuery(clazz, auditEvent);
138
139 if(description != null) {
140 query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
141 }
142
143 if(descriptionType != null) {
144 query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
145 }
146
147 query.add(AuditEntity.relatedId("feature").eq(f.getId()));
148 query.addProjection(AuditEntity.id().count());
149 count += (Long)query.getSingleResult();
150 }
151
152 return count;
153 } else {
154 AuditQuery query = makeAuditQuery(clazz, auditEvent);
155
156 if(description != null) {
157 query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
158 }
159 if(descriptionType != null) {
160 query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
161 }
162
163 query.addProjection(AuditEntity.id().count());
164 return (Long)query.getSingleResult();
165 }
166 }
167 }
168
169 @Override
170 public long countDescriptions(Class<? extends DescriptionBase> clazz, Boolean hasImages, Boolean hasText, Set<Feature> features) {
171 checkNotInPriorView("DescriptionDaoImpl.countDescriptions(Class<TYPE> type, Boolean hasImages, Boolean hasText, Set<Feature> features)");
172
173 Criteria inner = getCriteria(clazz);
174
175 Criteria elementsCriteria = inner.createCriteria("descriptionElements");
176 if(hasText != null) {
177 if(hasText) {
178 elementsCriteria.add(Restrictions.isNotEmpty("multilanguageText"));
179 } else {
180 elementsCriteria.add(Restrictions.isEmpty("multilanguageText"));
181 }
182 }
183
184 if(hasImages != null) {
185 if(hasImages) {
186 elementsCriteria.add(Restrictions.isNotEmpty("media"));
187 } else {
188 elementsCriteria.add(Restrictions.isEmpty("media"));
189 }
190 }
191
192 if(features != null && !features.isEmpty()) {
193 elementsCriteria.add(Restrictions.in("feature", features));
194 }
195
196 inner.setProjection(Projections.countDistinct("id"));
197
198 return (Long)inner.uniqueResult();
199 }
200
201 @Override
202 public long countTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes,
203 Set<NamedArea> geographicalScopes, Set<MarkerType> markerTypes, Set<DescriptionType> descriptionTypes) {
204 AuditEvent auditEvent = getAuditEventFromContext();
205 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
206 Criteria criteria = getCriteria(TaxonDescription.class);
207
208 if(taxon != null) {
209 criteria.add(Restrictions.eq("taxon", taxon));
210 }
211
212 if(scopes != null && !scopes.isEmpty()) {
213 Set<Integer> scopeIds = new HashSet<>();
214 for(DefinedTerm s : scopes) {
215 scopeIds.add(s.getId());
216 }
217 criteria.createCriteria("scopes").add(Restrictions.in("id", scopeIds));
218 }
219
220 if(geographicalScopes != null && !geographicalScopes.isEmpty()) {
221 Set<Integer> geoScopeIds = new HashSet<>();
222 for(NamedArea n : geographicalScopes) {
223 geoScopeIds.add(n.getId());
224 }
225 criteria.createCriteria("geoScopes").add(Restrictions.in("id", geoScopeIds));
226 }
227
228 addMarkerTypesCriterion(markerTypes, criteria);
229 addDescriptionTypesCriterion(descriptionTypes, criteria);
230
231 criteria.setProjection(Projections.rowCount());
232
233 return (Long)criteria.uniqueResult();
234 } else {
235 if((scopes == null || scopes.isEmpty())&& (geographicalScopes == null || geographicalScopes.isEmpty()) && (markerTypes == null || markerTypes.isEmpty())) {
236 AuditQuery query = makeAuditQuery(TaxonDescription.class,auditEvent);
237 if(taxon != null) {
238 query.add(AuditEntity.relatedId("taxon").eq(taxon.getId()));
239 }
240
241 query.addProjection(AuditEntity.id().count());
242
243 return (Long)query.getSingleResult();
244 } else {
245 throw new OperationNotSupportedInPriorViewException("countTaxonDescriptions(Taxon taxon, Set<Scope> scopes,Set<NamedArea> geographicalScopes)");
246 }
247 }
248 }
249
250 private void addDescriptionTypesCriterion(Set<DescriptionType> descriptionTypes, Criteria criteria) {
251 if(descriptionTypes != null && !descriptionTypes.isEmpty()) {
252 Set<Criterion> typeCriteria = new HashSet<>();
253 for (DescriptionType descriptionType : descriptionTypes) {
254 typeCriteria.add(Restrictions.sqlRestriction("{alias}.types like '%"+descriptionType.getKey()+"%'"));
255 }
256 criteria.add(Restrictions.and(typeCriteria.toArray(new Criterion[]{})));
257 }
258 }
259
260 /**
261 * @param markerTypes
262 * @param criteria
263 *
264 */
265 //TODO move to AnnotatableEntityDao(?)
266 private void addMarkerTypesCriterion(Set<MarkerType> markerTypes, Criteria criteria) {
267
268 if(markerTypes != null && !markerTypes.isEmpty()) {
269 Set<Integer> markerTypeIds = new HashSet<Integer>();
270 for(MarkerType markerType : markerTypes) {
271 markerTypeIds.add(markerType.getId());
272 }
273 criteria.createCriteria("markers").add(Restrictions.eq("flag", true))
274 .createAlias("markerType", "mt")
275 .add(Restrictions.in("mt.id", markerTypeIds));
276 } else if (markerTypes != null && markerTypes.isEmpty()){
277 //AT: added in case the projects requires an third state description, An empty Marker type set
278 }
279 }
280 @Override
281 public <T extends DescriptionElementBase> List<T> getDescriptionElements(
282 DescriptionBase description, Set<Feature> features,
283 Class<T> clazz, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
284 return getDescriptionElements(description, null, features, clazz, pageSize, pageNumber, propertyPaths);
285 }
286
287 @Override
288 public <T extends DescriptionElementBase> List<T> getDescriptionElements(
289 DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
290 Set<Feature> features,
291 Class<T> clazz,
292 Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
293
294 AuditEvent auditEvent = getAuditEventFromContext();
295 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
296 Criteria criteria = null;
297 if(clazz == null) {
298 criteria = getSession().createCriteria(DescriptionElementBase.class);
299 } else {
300 criteria = getSession().createCriteria(clazz);
301 }
302
303 if(description != null) {
304 criteria.add(Restrictions.eq("inDescription", description));
305 }
306 if(descriptionType != null) {
307 criteria.createAlias("inDescription", "d").add(Restrictions.eq("d.class", descriptionType));
308 }
309
310 if(features != null && !features.isEmpty()) {
311 criteria.add(Restrictions.in("feature", features));
312 }
313
314 if(pageSize != null) {
315 criteria.setMaxResults(pageSize);
316 if(pageNumber != null) {
317 criteria.setFirstResult(pageNumber * pageSize);
318 }
319 }
320
321 List<T> results = criteria.list();
322 defaultBeanInitializer.initializeAll(results, propertyPaths);
323 return results;
324 } else {
325 List<T> result = new ArrayList<T>();
326 if(features != null && !features.isEmpty()) {
327
328 for(Feature f : features) {
329 AuditQuery query = null;
330 if(clazz == null) {
331 query = getAuditReader().createQuery().forEntitiesAtRevision(DescriptionElementBase.class,auditEvent.getRevisionNumber());
332 } else {
333 query = getAuditReader().createQuery().forEntitiesAtRevision(clazz,auditEvent.getRevisionNumber());
334 }
335
336 if(description != null) {
337 query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
338 }
339
340 if(descriptionType != null) {
341 query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
342 }
343
344 query.add(AuditEntity.relatedId("feature").eq(f.getId()));
345 result.addAll(query.getResultList());
346 }
347 } else {
348 AuditQuery query = null;
349 if(clazz == null) {
350 query = getAuditReader().createQuery().forEntitiesAtRevision(DescriptionElementBase.class,auditEvent.getRevisionNumber());
351 } else {
352 query = getAuditReader().createQuery().forEntitiesAtRevision(clazz,auditEvent.getRevisionNumber());
353 }
354
355 if(description != null) {
356 query.add(AuditEntity.relatedId("inDescription").eq(description.getId()));
357 }
358
359 if(descriptionType != null) {
360 query.add(AuditEntity.property("inDescription.class").eq(descriptionType));
361 }
362
363 result = query.getResultList();
364 }
365
366 defaultBeanInitializer.initializeAll(result, propertyPaths);
367 return result;
368 }
369 }
370
371 @Override
372 public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScopes, Set<MarkerType> markerTypes, Set<DescriptionType> descriptionTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
373 AuditEvent auditEvent = getAuditEventFromContext();
374 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
375 Criteria criteria = getSession().createCriteria(TaxonDescription.class);
376
377 if(taxon != null) {
378 criteria.add(Restrictions.eq("taxon", taxon));
379 }
380
381 if(scopes != null && !scopes.isEmpty()) {
382 Set<Integer> scopeIds = new HashSet<Integer>();
383 for(DefinedTerm s : scopes) {
384 scopeIds.add(s.getId());
385 }
386 criteria.createCriteria("scopes").add(Restrictions.in("id", scopeIds));
387 }
388
389 if(geographicalScopes != null && !geographicalScopes.isEmpty()) {
390 Set<Integer> geoScopeIds = new HashSet<Integer>();
391 for(NamedArea n : geographicalScopes) {
392 geoScopeIds.add(n.getId());
393 }
394 criteria.createCriteria("geoScopes").add(Restrictions.in("id", geoScopeIds));
395 }
396
397 addMarkerTypesCriterion(markerTypes, criteria);
398 addDescriptionTypesCriterion(descriptionTypes, criteria);
399
400 if(pageSize != null) {
401 criteria.setMaxResults(pageSize);
402 if(pageNumber != null) {
403 criteria.setFirstResult(pageNumber * pageSize);
404 }
405 }
406
407 List<TaxonDescription> results = criteria.list();
408
409 defaultBeanInitializer.initializeAll(results, propertyPaths);
410
411 return results;
412 } else {
413 if((scopes == null || scopes.isEmpty())&& (geographicalScopes == null || geographicalScopes.isEmpty())&& (markerTypes == null || markerTypes.isEmpty())) {
414 AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonDescription.class,auditEvent.getRevisionNumber());
415 if(taxon != null) {
416 query.add(AuditEntity.relatedId("taxon").eq(taxon.getId()));
417 }
418
419 if(pageSize != null) {
420 query.setMaxResults(pageSize);
421 if(pageNumber != null) {
422 query.setFirstResult(pageNumber * pageSize);
423 } else {
424 query.setFirstResult(0);
425 }
426 }
427
428 List<TaxonDescription> results = query.getResultList();
429 defaultBeanInitializer.initializeAll(results, propertyPaths);
430 return results;
431 } else {
432 throw new OperationNotSupportedInPriorViewException("countTaxonDescriptions(Taxon taxon, Set<Scope> scopes,Set<NamedArea> geographicalScopes)");
433 }
434 }
435 }
436
437 @Override
438 public List<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
439 AuditEvent auditEvent = getAuditEventFromContext();
440 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
441 Criteria criteria = getSession().createCriteria(TaxonNameDescription.class);
442
443 if(name != null) {
444 criteria.add(Restrictions.eq("taxonName", name));
445 }
446
447 if(pageSize != null) {
448 criteria.setMaxResults(pageSize);
449 if(pageNumber != null) {
450 criteria.setFirstResult(pageNumber * pageSize);
451 }
452 }
453
454 List<TaxonNameDescription> results = criteria.list();
455
456 defaultBeanInitializer.initializeAll(results, propertyPaths);
457
458 return results;
459 } else {
460 AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonNameDescription.class,auditEvent.getRevisionNumber());
461
462 if(name != null) {
463 query.add(AuditEntity.relatedId("taxonName").eq(name.getId()));
464 }
465
466 if(pageSize != null) {
467 query.setMaxResults(pageSize);
468 if(pageNumber != null) {
469 query.setFirstResult(pageNumber * pageSize);
470 }
471 }
472
473 List<TaxonNameDescription> results = query.getResultList();
474 defaultBeanInitializer.initializeAll(results, propertyPaths);
475 return results;
476 }
477 }
478
479 @Override
480 public long countTaxonNameDescriptions(TaxonName name) {
481 AuditEvent auditEvent = getAuditEventFromContext();
482 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
483 Criteria criteria = getCriteria(TaxonNameDescription.class);
484
485 if(name != null) {
486 criteria.add(Restrictions.eq("taxonName", name));
487 }
488
489 criteria.setProjection(Projections.rowCount());
490
491 return (Long)criteria.uniqueResult();
492 } else {
493 AuditQuery query = makeAuditQuery(TaxonNameDescription.class,auditEvent);
494
495 if(name != null) {
496 query.add(AuditEntity.relatedId("taxonName").eq(name.getId()));
497 }
498
499 query.addProjection(AuditEntity.id().count());
500 return (Long)query.getSingleResult();
501 }
502 }
503
504 /**
505 * Should use a DetachedCriteria & subquery, but HHH-158 prevents this, for now.
506 *
507 * e.g. DetachedCriteria inner = DestachedCriteria.forClass(type);
508 *
509 * outer.add(Subqueries.propertyIn("id", inner));
510 */
511 @Override
512 public List<DescriptionBase> listDescriptions(Class<? extends DescriptionBase> clazz, Boolean hasImages, Boolean hasText, Set<Feature> features, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
513 checkNotInPriorView("DescriptionDaoImpl.listDescriptions(Class<TYPE> type, Boolean hasImages, Boolean hasText, Set<Feature> features, Integer pageSize, Integer pageNumber)");
514 Criteria inner = getCriteria(clazz);
515
516 Criteria elementsCriteria = inner.createCriteria("descriptionElements");
517 if(hasText != null) {
518 if(hasText) {
519 elementsCriteria.add(Restrictions.isNotEmpty("multilanguageText"));
520 } else {
521 elementsCriteria.add(Restrictions.isEmpty("multilanguageText"));
522 }
523 }
524
525 if(hasImages != null) {
526 if(hasImages) {
527 elementsCriteria.add(Restrictions.isNotEmpty("media"));
528 } else {
529 elementsCriteria.add(Restrictions.isEmpty("media"));
530 }
531 }
532
533 if(features != null && !features.isEmpty()) {
534 elementsCriteria.add(Restrictions.in("feature", features));
535 }
536
537 inner.setProjection(Projections.distinct(Projections.id()));
538
539 @SuppressWarnings("unchecked")
540 List<Object> intermediateResult = inner.list();
541
542 if(intermediateResult.isEmpty()) {
543 return new ArrayList<>();
544 }
545
546 Integer[] resultIds = new Integer[intermediateResult.size()];
547 for(int i = 0; i < resultIds.length; i++) {
548 resultIds[i] = (Integer)intermediateResult.get(i);
549 }
550
551 Criteria outer = getCriteria(clazz);
552
553 outer.add(Restrictions.in("id", resultIds));
554 addOrder(outer, orderHints);
555
556 addPageSizeAndNumber(outer, pageSize, pageNumber);
557
558 @SuppressWarnings({ "unchecked", "rawtypes" })
559 List<DescriptionBase> results = outer.list();
560 defaultBeanInitializer.initializeAll(results, propertyPaths);
561 return results;
562 }
563
564 @Override
565 public List<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
566 checkNotInPriorView("DescriptionDaoImpl.searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTermBase status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths)");
567
568 Criteria criteria = getSession().createCriteria(TaxonDescription.class);
569 Criteria elements = criteria.createCriteria("descriptionElements", "descriptionElement", Criteria.LEFT_JOIN);
570 elements.add(Restrictions.in("area", namedAreas.toArray()));
571
572 if(status != null) {
573 elements.add(Restrictions.eq("status", status));
574 }
575
576 ProjectionList projectionList = Projections.projectionList().add(Projections.id());
577
578 if(orderHints != null && !orderHints.isEmpty()) {
579 for(OrderHint orderHint : orderHints) {
580 projectionList = projectionList.add(Projections.property(orderHint.getPropertyName()));
581 }
582 }
583
584 criteria.setProjection(Projections.distinct(projectionList));
585
586 if(pageSize != null) {
587 criteria.setMaxResults(pageSize);
588 if(pageNumber != null) {
589 criteria.setFirstResult(pageNumber * pageSize);
590 }
591 }
592
593 addOrder(criteria,orderHints);
594
595 @SuppressWarnings("unchecked")
596 List<Object> intermediateResult = criteria.list();
597
598 if(intermediateResult.isEmpty()) {
599 return new ArrayList<>();
600 }
601
602 Integer[] resultIds = new Integer[intermediateResult.size()];
603 for(int i = 0; i < resultIds.length; i++) {
604 if(orderHints == null || orderHints.isEmpty()) {
605 resultIds[i] = (Integer)intermediateResult.get(i);
606 } else {
607 resultIds[i] = ((Number)((Object[])intermediateResult.get(i))[0]).intValue();
608 }
609 }
610
611 criteria = getSession().createCriteria(TaxonDescription.class);
612 criteria.add(Restrictions.in("id", resultIds));
613 addOrder(criteria,orderHints);
614
615 @SuppressWarnings("unchecked")
616 List<TaxonDescription> results = criteria.list();
617 defaultBeanInitializer.initializeAll(results, propertyPaths);
618 return results;
619 }
620
621 @Override
622 public List<CommonTaxonName> searchDescriptionByCommonName(String queryString, MatchMode matchMode, Integer pageSize, Integer pageNumber) {
623
624 Criteria crit = getSession().createCriteria(CommonTaxonName.class);
625 if (matchMode == MatchMode.EXACT) {
626 crit.add(Restrictions.eq("name", matchMode.queryStringFrom(queryString)));
627 } else {
628 crit.add(Restrictions.ilike("name", matchMode.queryStringFrom(queryString)));
629 }
630
631 if(pageSize != null) {
632 crit.setMaxResults(pageSize);
633 if(pageNumber != null) {
634 crit.setFirstResult(pageNumber * pageSize);
635 }
636 }
637 @SuppressWarnings("unchecked")
638 List<CommonTaxonName> results = crit.list();
639 return results;
640 }
641
642 @Override
643 public Integer countDescriptionByCommonName(String queryString, MatchMode matchMode) {
644 //TODO inprove performance
645 List<CommonTaxonName> results = searchDescriptionByCommonName(queryString, matchMode, null, null);
646 return results.size();
647 }
648
649 @Override
650 public DescriptionBase find(LSID lsid) {
651 DescriptionBase<?> descriptionBase = super.find(lsid);
652 if(descriptionBase != null) {
653 List<String> propertyPaths = new ArrayList<>();
654 propertyPaths.add("createdBy");
655 propertyPaths.add("updatedBy");
656 propertyPaths.add("taxon");
657 propertyPaths.add("taxonName");
658 propertyPaths.add("descriptionElements");
659 propertyPaths.add("descriptionElements.createdBy");
660 propertyPaths.add("descriptionElements.updatedBy");
661 propertyPaths.add("descriptionElements.feature");
662 propertyPaths.add("descriptionElements.multilanguageText");
663 propertyPaths.add("descriptionElements.multilanguageText.language");
664 propertyPaths.add("descriptionElements.area");
665 propertyPaths.add("descriptionElements.status");
666 propertyPaths.add("descriptionElements.modifyingText");
667 propertyPaths.add("descriptionElementsmodifyingText.language");
668 propertyPaths.add("descriptionElements.modifiers");
669
670 defaultBeanInitializer.initialize(descriptionBase, propertyPaths);
671 }
672 return descriptionBase;
673 }
674
675
676 @Override
677 public List<Integer> getIndividualAssociationSpecimenIDs(UUID taxonUuid,
678 Set<Feature> features, Integer pageSize,
679 Integer pageNumber, List<String> propertyPaths){
680 Query<Integer> query = prepareGetDescriptionElementForTaxon(taxonUuid, features, IndividualsAssociation.class, pageSize, pageNumber, "de.associatedSpecimenOrObservation.id");
681 List<Integer> results = query.list();
682 return results;
683 }
684
685 @Override
686 public List<SortableTaxonNodeQueryResult> getNodeOfIndividualAssociationForSpecimen(UUID specimenUuid, UUID classificationUuid){
687 String selectString = " new " +SortableTaxonNodeQueryResult.class.getName()+"(n.uuid, n.id, n.treeIndex, t.uuid, t.titleCache, t.name.titleCache, t.name.rank, n.parent.uuid) ";
688 Query<SortableTaxonNodeQueryResult> query = prepareGetIndividualAssociationForSpecimen(specimenUuid, classificationUuid, selectString);
689 @SuppressWarnings("unchecked")
690 List<SortableTaxonNodeQueryResult> results = query.list();
691 return results;
692 }
693
694 @Override
695 public <T extends DescriptionElementBase> List<T> getDescriptionElementForTaxon(
696 UUID taxonUuid, Set<Feature> features,
697 Class<T> type, Integer pageSize,
698 Integer pageNumber, List<String> propertyPaths) {
699
700 // LogUtils.setLevel("org.hibernate.SQL", Level.TRACE);
701 Query<T> query = prepareGetDescriptionElementForTaxon(taxonUuid, features, type, pageSize, pageNumber, "de");
702
703 if (logger.isDebugEnabled()){logger.debug(" dao: get list ...");}
704 List<T> results = query.list();
705 if (logger.isDebugEnabled()){logger.debug(" dao: initialize ...");}
706 defaultBeanInitializer.initializeAll(results, propertyPaths);
707 if (logger.isDebugEnabled()){logger.debug(" dao: initialize - DONE");}
708
709 // LogUtils.setLevel("org.hibernate.SQL", Level.WARN);
710 return results;
711 }
712
713 @Override
714 public <T extends DescriptionElementBase> long countDescriptionElementForTaxon(
715 UUID taxonUuid, Set<Feature> features, Class<T> type) {
716
717 Query<Long> query = prepareGetDescriptionElementForTaxon(taxonUuid, features, type, null, null, "count(de)");
718
719 return query.uniqueResult();
720 }
721
722 private <T extends DescriptionElementBase, R extends Object> Query<R> prepareGetDescriptionElementForTaxon(UUID taxonUuid,
723 Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, String selectString) {
724
725 String queryString = "SELECT " + selectString + " FROM DescriptionElementBase AS de" +
726 " LEFT JOIN de.inDescription AS d" +
727 " LEFT JOIN d.taxon AS t" +
728 " WHERE d.class = 'TaxonDescription' AND t.uuid = :taxon_uuid ";
729
730 if(type != null){
731 queryString += " and de.class = :type";
732 }
733 if (features != null && features.size() > 0){
734 queryString += " and de.feature in (:features) ";
735 }
736 Query<R> query = getSession().createQuery(queryString);
737
738 query.setParameter("taxon_uuid", taxonUuid);
739 if(type != null){
740 query.setParameter("type", type.getSimpleName());
741 }
742 if(features != null && features.size() > 0){
743 query.setParameterList("features", features) ;
744 }
745
746 addPageSizeAndNumber(query, pageSize, pageNumber);
747 return query;
748 }
749
750 private Query<SortableTaxonNodeQueryResult> prepareGetIndividualAssociationForSpecimen(UUID specimenUuid, UUID classificationUuid, String selectString) {
751
752 String queryString = "SELECT " + selectString + " FROM DescriptionElementBase AS de" +
753 " LEFT JOIN de.inDescription AS d" +
754 " LEFT JOIN d.taxon AS t" +
755 " LEFT JOIN t.taxonNodes AS n" +
756 " LEFT JOIN de.associatedSpecimenOrObservation AS specimen ";
757 String classificationString = "";
758 if (classificationUuid != null){
759 classificationString = " LEFT JOIN n.classification AS c ";
760 }
761 String whereString = " WHERE specimen.uuid = :specimen_uuid";
762 if (classificationUuid != null){
763 whereString = whereString + " AND c.uuid = :classifcationUuid";
764 }
765
766 Query<SortableTaxonNodeQueryResult> query = getSession().createQuery(queryString + classificationString + whereString, SortableTaxonNodeQueryResult.class);
767
768 query.setParameter("specimen_uuid", specimenUuid);
769 if (classificationUuid != null){
770 query.setParameter("classifcationUuid", classificationUuid);
771 }
772
773 return query;
774 }
775
776 @Override
777 public List<Media> listTaxonDescriptionMedia(UUID taxonUuid,
778 Boolean limitToGalleries, Set<MarkerType> markerTypes,
779 Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
780
781 AuditEvent auditEvent = getAuditEventFromContext();
782 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
783 String queryString = " SELECT media " +
784 getTaxonDescriptionMediaQueryString(
785 taxonUuid, limitToGalleries, markerTypes);
786 queryString +=
787 " GROUP BY media "
788 // " ORDER BY index(media) " //not functional
789 ;
790
791 Query<Media> query = getSession().createQuery(queryString, Media.class);
792
793 setTaxonDescriptionMediaParameters(query, taxonUuid, limitToGalleries, markerTypes);
794 // addMarkerTypesCriterion(markerTypes, hql);
795
796 addPageSizeAndNumber(query, pageSize, pageNumber);
797 List<Media> results = query.list();
798 defaultBeanInitializer.initializeAll(results, propertyPaths);
799
800 return results;
801 } else {
802 throw new OperationNotSupportedInPriorViewException("countTaxonDescriptionMedia(UUID taxonUuid, boolean restrictToGalleries)");
803 }
804 }
805
806 @Override
807 public int countTaxonDescriptionMedia(UUID taxonUuid,
808 Boolean limitToGalleries, Set<MarkerType> markerTypes) {
809 AuditEvent auditEvent = getAuditEventFromContext();
810 if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
811 String queryString = " SELECT count(DISTINCT media) " +
812 getTaxonDescriptionMediaQueryString(
813 taxonUuid, limitToGalleries, markerTypes);
814
815 Query<Long> query = getSession().createQuery(queryString, Long.class);
816 setTaxonDescriptionMediaParameters(query, taxonUuid, limitToGalleries, markerTypes);
817 return query.uniqueResult().intValue();
818 }else{
819 throw new OperationNotSupportedInPriorViewException("countTaxonDescriptionMedia(UUID taxonUuid)");
820 }
821
822 }
823
824 private void setTaxonDescriptionMediaParameters(Query query, UUID taxonUuid, Boolean limitToGalleries, Set<MarkerType> markerTypes) {
825 if(taxonUuid != null){
826 query.setParameter("uuid", taxonUuid);
827 }
828 }
829
830 /**
831 * @param taxonUuid
832 * @param restrictToGalleries
833 * @param markerTypes
834 * @return
835 */
836 private String getTaxonDescriptionMediaQueryString(UUID taxonUuid,
837 Boolean restrictToGalleries, Set<MarkerType> markerTypes) {
838 String fromQueryString =
839 " FROM DescriptionElementBase as deb INNER JOIN " +
840 " deb.inDescription as td "
841 + " INNER JOIN td.taxon as t "
842 + " JOIN deb.media as media "
843 + " LEFT JOIN td.markers marker ";
844
845 String whereQueryString = " WHERE (1=1) ";
846 if (taxonUuid != null){
847 whereQueryString += " AND t.uuid = :uuid ";
848 }
849 if (restrictToGalleries){
850 whereQueryString += " AND td.imageGallery is true ";
851 }
852 if (markerTypes != null && !markerTypes.isEmpty()){
853 whereQueryString += " AND (1=0";
854 for (MarkerType markerType : markerTypes){
855 whereQueryString += " OR ( marker.markerType.id = " + markerType.getId() + " AND marker.flag is true)";
856
857 }
858 whereQueryString += ") ";
859 }
860
861 return fromQueryString + whereQueryString;
862
863 }
864
865 @SuppressWarnings("unchecked")
866 @Override
867 public List<TermDto> listNamedAreasInUse(boolean includeAllParents, Integer pageSize, Integer pageNumber) {
868
869 // LogUtils.setLevel("org.hibernate.SQL", Level.TRACE);
870
871 StringBuilder queryString = new StringBuilder(
872 "SELECT DISTINCT a.id, a.partOf.id"
873 + " FROM Distribution AS d JOIN d.area AS a");
874 Query<Object[]> query = getSession().createQuery(queryString.toString(), Object[].class);
875
876 List<Object[]> areasInUse = query.list();
877 List<Object[]> parentResults = new ArrayList<>();
878
879 if(!areasInUse.isEmpty()) {
880 Set<Object> allAreaIds = new HashSet<>(areasInUse.size());
881
882 if(includeAllParents) {
883 // find all parent nodes
884 String allAreasQueryStr = "select a.id, a.partOf.id from NamedArea as a";
885 query = getSession().createQuery(allAreasQueryStr, Object[].class);
886 List<Object[]> allAreasResult = query.list();
887 Map<Object, Object> allAreasMap = ArrayUtils.toMap(allAreasResult.toArray());
888
889 Set<Object> parents = new HashSet<>();
890
891 for(Object[] leaf : areasInUse) {
892 allAreaIds.add(leaf[0]);
893 Object parentId = leaf[1];
894 while (parentId != null) {
895 if(parents.contains(parentId)) {
896 // break if the parent already is in the set
897 break;
898 }
899 parents.add(parentId);
900 parentId = allAreasMap.get(parentId);
901 }
902 }
903 allAreaIds.addAll(parents);
904 } else {
905 // only add the ids found so far
906 for(Object[] leaf : areasInUse) {
907 allAreaIds.add(leaf[0]);
908 }
909 }
910
911 // NOTE can't use "select new TermDto(distinct a.uuid, r , a.vocabulary.uuid) since we will get multiple
912 // rows for a term with multiple representations
913 String parentAreasQueryStr = TermDto.getTermDtoSelect("NamedArea")
914 + "where a.id in (:allAreaIds) order by a.idInVocabulary";
915 query = getSession().createQuery(parentAreasQueryStr, Object[].class);
916 query.setParameterList("allAreaIds", allAreaIds);
917
918 addPageSizeAndNumber(query, pageSize, pageNumber);
919 parentResults = query.list();
920 }
921 List<TermDto> dtoList = TermDto.termDtoListFrom(parentResults);
922
923 return dtoList;
924 }
925
926
927
928
929
930 }