ref #7509 Add "computed" flag to description
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DescriptionServiceImpl.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.api.service;
11
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.UUID;
22
23 import org.apache.commons.lang.StringUtils;
24 import org.apache.log4j.Logger;
25 import org.springframework.beans.factory.annotation.Autowired;
26 import org.springframework.stereotype.Service;
27 import org.springframework.transaction.annotation.Transactional;
28
29 import eu.etaxonomy.cdm.api.service.pager.Pager;
30 import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
31 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
32 import eu.etaxonomy.cdm.api.utility.DescriptionUtility;
33 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
34 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
35 import eu.etaxonomy.cdm.model.common.Annotation;
36 import eu.etaxonomy.cdm.model.common.AnnotationType;
37 import eu.etaxonomy.cdm.model.common.CdmBase;
38 import eu.etaxonomy.cdm.model.common.DefinedTerm;
39 import eu.etaxonomy.cdm.model.common.Language;
40 import eu.etaxonomy.cdm.model.common.Marker;
41 import eu.etaxonomy.cdm.model.common.MarkerType;
42 import eu.etaxonomy.cdm.model.common.TermVocabulary;
43 import eu.etaxonomy.cdm.model.description.CategoricalData;
44 import eu.etaxonomy.cdm.model.description.DescriptionBase;
45 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
46 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
47 import eu.etaxonomy.cdm.model.description.Distribution;
48 import eu.etaxonomy.cdm.model.description.Feature;
49 import eu.etaxonomy.cdm.model.description.FeatureTree;
50 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
51 import eu.etaxonomy.cdm.model.description.QuantitativeData;
52 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
53 import eu.etaxonomy.cdm.model.description.TaxonDescription;
54 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
55 import eu.etaxonomy.cdm.model.description.TextData;
56 import eu.etaxonomy.cdm.model.location.NamedArea;
57 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
58 import eu.etaxonomy.cdm.model.media.Media;
59 import eu.etaxonomy.cdm.model.name.TaxonName;
60 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
61 import eu.etaxonomy.cdm.model.taxon.Taxon;
62 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
63 import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
64 import eu.etaxonomy.cdm.persistence.dao.common.ITermVocabularyDao;
65 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
66 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionElementDao;
67 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
68 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureDao;
69 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureNodeDao;
70 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureTreeDao;
71 import eu.etaxonomy.cdm.persistence.dao.description.IStatisticalMeasurementValueDao;
72 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
73 import eu.etaxonomy.cdm.persistence.dto.TermDto;
74 import eu.etaxonomy.cdm.persistence.query.OrderHint;
75 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
76
77 /**
78 * @author a.mueller
79 * @since 24.06.2008
80 * @version 1.0
81 */
82 /**
83 * @author a.kohlbecker
84 * @since Dec 5, 2013
85 *
86 */
87 @Service
88 @Transactional(readOnly = true)
89 public class DescriptionServiceImpl
90 extends IdentifiableServiceBase<DescriptionBase,IDescriptionDao>
91 implements IDescriptionService {
92
93 private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
94
95 protected IDescriptionElementDao descriptionElementDao;
96 protected IFeatureTreeDao featureTreeDao;
97 protected IFeatureNodeDao featureNodeDao;
98 protected IFeatureDao featureDao;
99 protected ITermVocabularyDao vocabularyDao;
100 protected IDefinedTermDao definedTermDao;
101 protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
102 protected ITaxonDao taxonDao;
103 protected IDescriptiveDataSetDao dataSetDao;
104
105 //TODO change to Interface
106 private NaturalLanguageGenerator naturalLanguageGenerator;
107
108 @Autowired
109 protected void setFeatureTreeDao(IFeatureTreeDao featureTreeDao) {
110 this.featureTreeDao = featureTreeDao;
111 }
112
113 @Autowired
114 protected void setFeatureNodeDao(IFeatureNodeDao featureNodeDao) {
115 this.featureNodeDao = featureNodeDao;
116 }
117
118 @Autowired
119 protected void setFeatureDao(IFeatureDao featureDao) {
120 this.featureDao = featureDao;
121 }
122
123 @Autowired
124 protected void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
125 this.vocabularyDao = vocabularyDao;
126 }
127
128 @Autowired
129 protected void setDefinedTermDao(IDefinedTermDao definedTermDao) {
130 this.definedTermDao = definedTermDao;
131 }
132
133 @Autowired
134 protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao) {
135 this.statisticalMeasurementValueDao = statisticalMeasurementValueDao;
136 }
137
138 @Autowired
139 protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao) {
140 this.descriptionElementDao = descriptionElementDao;
141 }
142
143 @Autowired
144 protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator) {
145 this.naturalLanguageGenerator = naturalLanguageGenerator;
146 }
147
148 @Autowired
149 protected void setTaxonDao(ITaxonDao taxonDao) {
150 this.taxonDao = taxonDao;
151 }
152
153 @Autowired
154 protected void setDataSetDao(IDescriptiveDataSetDao dataSetDao) {
155 this.dataSetDao = dataSetDao;
156 }
157
158 /**
159 *
160 */
161 public DescriptionServiceImpl() {
162 logger.debug("Load DescriptionService Bean");
163 }
164
165
166 @Override
167 @Transactional(readOnly = false)
168 public void updateTitleCache(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
169 if (clazz == null){
170 clazz = DescriptionBase.class;
171 }
172 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
173 }
174
175
176 @Override
177 public TermVocabulary<Feature> getDefaultFeatureVocabulary(){
178 String uuidFeature = "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
179 UUID featureUuid = UUID.fromString(uuidFeature);
180 return vocabularyDao.findByUuid(featureUuid);
181 }
182
183 @Override
184 @Autowired
185 protected void setDao(IDescriptionDao dao) {
186 this.dao = dao;
187 }
188
189 @Override
190 public long count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
191 return dao.countDescriptions(type, hasImages, hasText, feature);
192 }
193
194 @Override
195 public <T extends DescriptionElementBase> Pager<T> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
196 Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
197
198 List<T> results = listDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
199 return new DefaultPagerImpl<>(pageNumber, results.size(), pageSize, results);
200 }
201
202 @Override
203 @Deprecated
204 public <T extends DescriptionElementBase> Pager<T> getDescriptionElements(DescriptionBase description,
205 Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
206 return pageDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
207 }
208
209
210
211 @Override
212 public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
213 Class<? extends DescriptionBase> descriptionType, Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber,
214 List<String> propertyPaths) {
215
216 long numberOfResults = dao.countDescriptionElements(description, descriptionType, features, type);
217 List<T> results = new ArrayList<T>();
218 if(AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)) {
219 results = dao.getDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
220 }
221 return results;
222
223 }
224
225
226 @Override
227 @Deprecated
228 public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
229 Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
230
231 return listDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
232 }
233
234 @Override
235 public Pager<Annotation> getDescriptionElementAnnotations(DescriptionElementBase annotatedObj, MarkerType status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
236 long numberOfResults = descriptionElementDao.countAnnotations(annotatedObj, status);
237
238 List<Annotation> results = new ArrayList<>();
239 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
240 results = descriptionElementDao.getAnnotations(annotatedObj, status, pageSize, pageNumber, orderHints, propertyPaths);
241 }
242
243 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
244 }
245
246
247 @Override
248 public Pager<Media> getMedia(DescriptionElementBase descriptionElement, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
249 Integer numberOfResults = descriptionElementDao.countMedia(descriptionElement);
250
251 List<Media> results = new ArrayList<Media>();
252 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
253 results = descriptionElementDao.getMedia(descriptionElement, pageSize, pageNumber, propertyPaths);
254 }
255
256 return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
257 }
258
259 @Override
260 public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
261 Set<MarkerType> markerTypes = null;
262 return pageTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
263 }
264
265 @Override
266 public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
267 Set<MarkerType> markerTypes = null;
268 return listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
269 }
270
271 @Override
272 public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
273 long numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes);
274
275 List<TaxonDescription> results = new ArrayList<>();
276 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
277 results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
278 }
279
280 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
281 }
282
283 @Override
284 public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
285 List<TaxonDescription> results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
286 return results;
287 }
288
289
290 @Override
291 public List<Media> listTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths){
292 return this.dao.listTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes, pageSize, pageNumber, propertyPaths);
293 }
294
295 @Override
296 public int countTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes){
297 return this.dao.countTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes);
298 }
299
300 @Override
301 @Deprecated
302 public DistributionTree getOrderedDistributions(
303 Set<TaxonDescription> taxonDescriptions,
304 boolean subAreaPreference,
305 boolean statusOrderPreference,
306 Set<MarkerType> hiddenAreaMarkerTypes,
307 Set<NamedAreaLevel> omitLevels, List<String> propertyPaths){
308
309 List<Distribution> distList = new ArrayList<Distribution>();
310
311 List<UUID> uuids = new ArrayList<UUID>();
312 for (TaxonDescription taxonDescription : taxonDescriptions) {
313 if (! taxonDescription.isImageGallery()){ //image galleries should not have descriptions, but better filter fully on DTYPE of description element
314 uuids.add(taxonDescription.getUuid());
315 }
316 }
317
318 List<DescriptionBase> desclist = dao.list(uuids, null, null, null, propertyPaths);
319 for (DescriptionBase desc : desclist) {
320 if (desc.isInstanceOf(TaxonDescription.class)){
321 Set<DescriptionElementBase> elements = desc.getElements();
322 for (DescriptionElementBase element : elements) {
323 if (element.isInstanceOf(Distribution.class)) {
324 Distribution distribution = (Distribution) element;
325 if(distribution.getArea() != null){
326 distList.add(distribution);
327 }
328 }
329 }
330 }
331 }
332
333 //old
334 // for (TaxonDescription taxonDescription : taxonDescriptions) {
335 // if (logger.isDebugEnabled()){ logger.debug("load taxon description " + taxonDescription.getUuid());}
336 // //TODO why not loading all description via .list ? This may improve performance
337 // taxonDescription = (TaxonDescription) dao.load(taxonDescription.getUuid(), propertyPaths);
338 // Set<DescriptionElementBase> elements = taxonDescription.getElements();
339 // for (DescriptionElementBase element : elements) {
340 // if (element.isInstanceOf(Distribution.class)) {
341 // Distribution distribution = (Distribution) element;
342 // if(distribution.getArea() != null){
343 // distList.add(distribution);
344 // }
345 // }
346 // }
347 // }
348
349 if (logger.isDebugEnabled()){logger.debug("filter tree for " + distList.size() + " distributions ...");}
350
351 // filter distributions
352 Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distList, hiddenAreaMarkerTypes, true, statusOrderPreference, false);
353 distList.clear();
354 distList.addAll(filteredDistributions);
355
356 return DescriptionUtility.orderDistributions(definedTermDao, omitLevels, distList, hiddenAreaMarkerTypes, null);
357 }
358
359
360 @Override
361 public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
362 long numberOfResults = dao.countTaxonNameDescriptions(name);
363
364 List<TaxonNameDescription> results = new ArrayList<>();
365 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
366 results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
367 }
368
369 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
370 }
371
372
373 @Override
374 public Pager<DescriptionBase> page(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText, Set<Feature> feature, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
375 long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
376
377 @SuppressWarnings("rawtypes")
378 List<DescriptionBase> results = new ArrayList<>();
379 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
380 results = dao.listDescriptions(type, hasImages, hasText, feature, pageSize, pageNumber,orderHints,propertyPaths);
381 }
382
383 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
384 }
385
386 /**
387 * FIXME Candidate for harmonization
388 * Rename: searchByDistribution
389 */
390 @Override
391 public Pager<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm presence, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
392 long numberOfResults = dao.countDescriptionByDistribution(namedAreas, presence);
393
394 List<TaxonDescription> results = new ArrayList<>();
395 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
396 results = dao.searchDescriptionByDistribution(namedAreas, presence, pageSize, pageNumber,orderHints,propertyPaths);
397 }
398
399 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
400 }
401
402 /**
403 * FIXME Candidate for harmonization
404 * move: descriptionElementService.search
405 */
406 @Override
407 public Pager<DescriptionElementBase> searchElements(Class<? extends DescriptionElementBase> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
408 long numberOfResults = descriptionElementDao.count(clazz, queryString);
409
410 List<DescriptionElementBase> results = new ArrayList<>();
411 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
412 results = descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
413 }
414
415 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
416 }
417
418 /**
419 * FIXME Candidate for harmonization
420 * descriptionElementService.find
421 */
422 @Override
423 public DescriptionElementBase getDescriptionElementByUuid(UUID uuid) {
424 return descriptionElementDao.findByUuid(uuid);
425 }
426
427 /**
428 * FIXME Candidate for harmonization
429 * descriptionElementService.load
430 */
431 @Override
432 public DescriptionElementBase loadDescriptionElement(UUID uuid, List<String> propertyPaths) {
433 return descriptionElementDao.load(uuid, propertyPaths);
434 }
435
436 /**
437 * FIXME Candidate for harmonization
438 * descriptionElementService.save
439 */
440 @Override
441 @Transactional(readOnly = false)
442 public UUID saveDescriptionElement(DescriptionElementBase descriptionElement) {
443 return descriptionElementDao.save(descriptionElement).getUuid();
444 }
445
446 /**
447 * FIXME Candidate for harmonization
448 * descriptionElementService.save
449 */
450 @Override
451 @Transactional(readOnly = false)
452 public Map<UUID, DescriptionElementBase> saveDescriptionElement(Collection<DescriptionElementBase> descriptionElements) {
453 return descriptionElementDao.saveAll(descriptionElements);
454 }
455
456 /**
457 * FIXME Candidate for harmonization
458 * descriptionElementService.delete
459 */
460 @Override
461 public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
462 return descriptionElementDao.delete(descriptionElement);
463 }
464
465
466 /* (non-Javadoc)
467 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescriptionElement(java.util.UUID)
468 */
469 @Override
470 public UUID deleteDescriptionElement(UUID descriptionElementUuid) {
471 return deleteDescriptionElement(descriptionElementDao.load(descriptionElementUuid));
472 }
473
474 @Override
475 @Transactional(readOnly = false)
476 public DeleteResult deleteDescription(DescriptionBase description) {
477 DeleteResult deleteResult = new DeleteResult();
478 description = load(description.getId(), Arrays.asList("descriptiveDataSets"));//avoid lazy init exception
479
480 if (description instanceof TaxonDescription){
481 TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
482 Taxon tax = taxDescription.getTaxon();
483 tax.removeDescription(taxDescription, true);
484 deleteResult.addUpdatedObject(tax);
485 }
486 else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
487 SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(description, SpecimenDescription.class);
488 SpecimenOrObservationBase specimen = specimenDescription.getDescribedSpecimenOrObservation();
489 specimen.removeDescription(specimenDescription);
490 deleteResult.addUpdatedObject(specimen);
491 }
492
493 Set<DescriptiveDataSet> descriptiveDataSets = description.getDescriptiveDataSets();
494 for (Iterator<DescriptiveDataSet> iterator = descriptiveDataSets.iterator(); iterator.hasNext();) {
495 iterator.next().removeDescription(description);
496 }
497
498 dao.delete(description);
499 deleteResult.addDeletedObject(description);
500 deleteResult.setCdmEntity(description);
501
502
503 return deleteResult;
504 }
505
506
507 /* (non-Javadoc)
508 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescription(java.util.UUID)
509 */
510 @Override
511 @Transactional(readOnly = false)
512 public DeleteResult deleteDescription(UUID descriptionUuid) {
513 return deleteDescription(dao.load(descriptionUuid));
514 }
515
516
517 @Override
518 public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
519 return vocabularyDao.findByUuid(uuid);
520 }
521
522 @Override
523 @Deprecated
524 public <T extends DescriptionElementBase> List<T> getDescriptionElementsForTaxon(
525 Taxon taxon, Set<Feature> features,
526 Class<T> type, Integer pageSize,
527 Integer pageNumber, List<String> propertyPaths) {
528 return listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
529 }
530
531 @Override
532 public <T extends DescriptionElementBase> List<T> listDescriptionElementsForTaxon(
533 Taxon taxon, Set<Feature> features,
534 Class<T> type, Integer pageSize,
535 Integer pageNumber, List<String> propertyPaths) {
536 return dao.getDescriptionElementForTaxon(taxon.getUuid(), features, type, pageSize, pageNumber, propertyPaths);
537 }
538
539 @Override
540 public <T extends DescriptionElementBase> Pager<T> pageDescriptionElementsForTaxon(
541 Taxon taxon, Set<Feature> features,
542 Class<T> type, Integer pageSize,
543 Integer pageNumber, List<String> propertyPaths) {
544 if (logger.isDebugEnabled()){logger.debug(" get count ...");}
545 Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type);
546 List<T> descriptionElements;
547 if(AbstractPagerImpl.hasResultsInRange(count, pageNumber, pageSize)){ // no point checking again
548 if (logger.isDebugEnabled()){logger.debug(" get list ...");}
549 descriptionElements = listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
550 } else {
551 descriptionElements = new ArrayList<T>(0);
552 }
553 if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
554 return new DefaultPagerImpl<T>(pageNumber, count, pageSize, descriptionElements);
555 }
556
557
558 /* (non-Javadoc)
559 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#generateNaturalLanguageDescription(eu.etaxonomy.cdm.model.description.FeatureTree, eu.etaxonomy.cdm.model.description.TaxonDescription, eu.etaxonomy.cdm.model.common.Language, java.util.List)
560 */
561 @Override
562 public String generateNaturalLanguageDescription(FeatureTree featureTree,
563 TaxonDescription description, List<Language> preferredLanguages, String separator) {
564
565 Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
566
567 description = (TaxonDescription)load(description.getUuid());
568 featureTree = featureTreeDao.load(featureTree.getUuid());
569
570 StringBuilder naturalLanguageDescription = new StringBuilder();
571
572 MarkerType useMarkerType = (MarkerType) definedTermDao.load(UUID.fromString("2e6e42d9-e92a-41f4-899b-03c0ac64f039"));
573 boolean isUseDescription = false;
574 if(!description.getMarkers().isEmpty()) {
575 for (Marker marker: description.getMarkers()) {
576 MarkerType markerType = marker.getMarkerType();
577 if (markerType.equals(useMarkerType)) {
578 isUseDescription = true;
579 }
580
581 }
582 }
583
584 if(description.hasStructuredData() && !isUseDescription){
585
586
587 String lastCategory = null;
588 String categorySeparator = ". ";
589
590 List<TextData> textDataList;
591 TextData naturalLanguageDescriptionText = null;
592
593 boolean useMicroFormatQuantitativeDescriptionBuilder = false;
594
595 if(useMicroFormatQuantitativeDescriptionBuilder){
596
597 MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
598 naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
599 naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
600
601 } else {
602
603 naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
604 featureTree,
605 (description),
606 lang);
607 }
608
609 return naturalLanguageDescriptionText.getText(lang);
610
611 //
612 // boolean doItBetter = false;
613 //
614 // for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
615 // if(textData.getMultilanguageText().size() > 0){
616 //
617 // if (!textData.getFeature().equals(Feature.UNKNOWN())) {
618 // String featureLabel = textData.getFeature().getLabel(lang);
619 //
620 // if(doItBetter){
621 // /*
622 // * WARNING
623 // * The code lines below are desinged to handle
624 // * a special case where as the feature label contains
625 // * hierarchical information on the features. This code
626 // * exist only as a base for discussion, and is not
627 // * intendet to be used in production.
628 // */
629 // featureLabel = StringUtils.remove(featureLabel, '>');
630 //
631 // String[] labelTokens = StringUtils.split(featureLabel, '<');
632 // if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
633 // if(naturalLanguageDescription.length() > 0){
634 // naturalLanguageDescription.append(separator);
635 // }
636 // naturalLanguageDescription.append(labelTokens[1]);
637 // } else {
638 // if(naturalLanguageDescription.length() > 0){
639 // naturalLanguageDescription.append(categorySeparator);
640 // }
641 // naturalLanguageDescription.append(StringUtils.join(labelTokens));
642 // }
643 // lastCategory = labelTokens[0];
644 // // end of demo code
645 // } else {
646 // if(naturalLanguageDescription.length() > 0){
647 // naturalLanguageDescription.append(separator);
648 // }
649 // naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
650 // }
651 // } else {
652 // if(naturalLanguageDescription.length() > 0){
653 // naturalLanguageDescription.append(separator);
654 // }
655 // }
656 // String text = textData.getMultilanguageText().values().iterator().next().getText();
657 // naturalLanguageDescription.append(text);
658 //
659 // }
660 // }
661
662 }
663 else if (isUseDescription) {
664 //AT: Left Blank in case we need to generate a Natural language text string.
665 }
666 return naturalLanguageDescription.toString();
667 }
668
669
670 @Override
671 public boolean hasStructuredData(DescriptionBase<?> description) {
672 return load(description.getUuid()).hasStructuredData();
673 }
674
675
676 @Override
677 @Transactional(readOnly = false)
678 public UpdateResult moveDescriptionElementsToDescription(
679 Collection<DescriptionElementBase> descriptionElements,
680 DescriptionBase targetDescription,
681 boolean isCopy) {
682
683 UpdateResult result = new UpdateResult();
684 if (descriptionElements.isEmpty() ){
685 return result;
686 }
687
688 if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
689 //if the descriptionElements collection is the elements set of a description, put it in a separate set before to avoid concurrent modification exceptions
690 descriptionElements = new HashSet<DescriptionElementBase>(descriptionElements);
691 // descriptionElementsTmp.addAll(descriptionElements);
692 // descriptionElements = descriptionElementsTmp;
693 }
694 for (DescriptionElementBase element : descriptionElements){
695 DescriptionBase<?> description = element.getInDescription();
696 try {
697 DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
698 targetDescription.addElement(newElement);
699 } catch (CloneNotSupportedException e) {
700 throw new RuntimeException ("Clone not yet implemented for class " + element.getClass().getName(), e);
701 }
702 if (! isCopy){
703 description.removeElement(element);
704 if (description.getElements().isEmpty()){
705 if (description instanceof TaxonDescription){
706 TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
707 if (taxDescription.getTaxon() != null){
708 taxDescription.getTaxon().removeDescription((TaxonDescription)description);
709 }
710 }
711 dao.delete(description);
712
713 }else{
714 dao.saveOrUpdate(description);
715 result.addUpdatedObject(description);
716 }
717 }
718
719
720 }
721 dao.saveOrUpdate(targetDescription);
722 result.addUpdatedObject(targetDescription);
723 if (targetDescription instanceof TaxonDescription){
724 result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
725 }
726 return result;
727 }
728
729 @Override
730 @Transactional(readOnly = false)
731 public UpdateResult moveDescriptionElementsToDescription(
732 Set<UUID> descriptionElementUUIDs,
733 UUID targetDescriptionUuid,
734 boolean isCopy) {
735 Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
736 for(UUID deUuid : descriptionElementUUIDs) {
737 descriptionElements.add(descriptionElementDao.load(deUuid));
738 }
739 DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
740
741 return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
742 }
743
744 @Override
745 @Transactional(readOnly = false)
746 public UpdateResult moveDescriptionElementsToDescription(
747 Set<UUID> descriptionElementUUIDs,
748 UUID targetTaxonUuid,
749 String moveMessage,
750 boolean isCopy) {
751 Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
752 DescriptionBase targetDescription = TaxonDescription.NewInstance(targetTaxon);
753 targetDescription.setTitleCache(moveMessage, true);
754 Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
755 annotation.setAnnotationType(AnnotationType.TECHNICAL());
756 targetDescription.addAnnotation(annotation);
757
758 targetDescription = dao.save(targetDescription);
759 Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
760 for(UUID deUuid : descriptionElementUUIDs) {
761 descriptionElements.add(descriptionElementDao.load(deUuid));
762 }
763
764 return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
765 }
766
767 @Override
768 public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
769 Integer pageNumber){
770 List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
771 int startIndex= pageNumber * pageSize;
772 int toIndex = Math.min(startIndex + pageSize, results.size());
773 List<TermDto> page = results.subList(startIndex, toIndex);
774 return new DefaultPagerImpl<TermDto>(pageNumber, results.size(), pageSize, page);
775 }
776
777
778 @Override
779 @Transactional(readOnly = false)
780 public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon) {
781 List<TaxonDescription> descriptions = new ArrayList(sourceTaxon.getDescriptions());
782 UpdateResult result = new UpdateResult();
783 result.addUpdatedObject(sourceTaxon);
784 result.addUpdatedObject(targetTaxon);
785 for(TaxonDescription description : descriptions){
786
787 String moveMessage = String.format("Description moved from %s", sourceTaxon);
788 if(description.isProtectedTitleCache()){
789 String separator = "";
790 if(!StringUtils.isBlank(description.getTitleCache())){
791 separator = " - ";
792 }
793 description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
794 }
795 Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
796 annotation.setAnnotationType(AnnotationType.TECHNICAL());
797 description.addAnnotation(annotation);
798 targetTaxon.addDescription(description);
799 }
800 return result;
801 }
802
803 @Override
804 @Transactional(readOnly = false)
805 public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid) {
806 Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
807 Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
808 return moveTaxonDescriptions(sourceTaxon, targetTaxon);
809
810 }
811
812 @Override
813 @Transactional(readOnly = false)
814 public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid){
815 UpdateResult result = new UpdateResult();
816 TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
817
818 Taxon sourceTaxon = description.getTaxon();
819 String moveMessage = String.format("Description moved from %s", sourceTaxon);
820 if(description.isProtectedTitleCache()){
821 String separator = "";
822 if(!StringUtils.isBlank(description.getTitleCache())){
823 separator = " - ";
824 }
825 description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
826 }
827 Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
828 annotation.setAnnotationType(AnnotationType.TECHNICAL());
829 description.addAnnotation(annotation);
830 Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
831 targetTaxon.addDescription(description);
832 result.addUpdatedObject(targetTaxon);
833 result.addUpdatedObject(sourceTaxon);
834 // dao.merge(description);
835 return result;
836
837 }
838
839 @Override
840 public UpdateResult aggregateDescription(UUID taxonUuid, Collection<UUID> descriptionUuids, UUID descriptiveDataSet) {
841 UpdateResult result = new UpdateResult();
842 Map<Feature, List<DescriptionElementBase>> featureToElementMap = new HashMap<>();
843
844 DescriptiveDataSet dataSet = dataSetDao.load(descriptiveDataSet);
845 TaxonBase taxonBase = taxonDao.load(taxonUuid);
846 if(!(taxonBase instanceof Taxon)){
847 result.addException(new ClassCastException("The given taxonUUID does not belong to a taxon"));
848 result.setError();
849 return result;
850 }
851 Taxon taxon = (Taxon)taxonBase;
852
853 //extract all description elements
854 Set<DescriptionBase> descriptions = dataSet.getDescriptions();
855 for (DescriptionBase descriptionBase : descriptions) {
856 List<DescriptionElementBase> descriptionElements = listDescriptionElements(descriptionBase, null, dataSet.getDescriptiveSystem().getDistinctFeatures(), null, null, null, null);
857 for (DescriptionElementBase descriptionElement : descriptionElements) {
858 List<DescriptionElementBase> list = featureToElementMap.get(descriptionElement.getFeature());
859 if(list==null){
860 list = new ArrayList<>();
861 }
862 list.add(descriptionElement);
863 featureToElementMap.put(descriptionElement.getFeature(), list);
864 }
865 }
866
867 TaxonDescription description = TaxonDescription.NewInstance(taxon);
868 description.setTitleCache("[Aggregation] "+dataSet.getTitleCache(), true);
869 description.addMarker(Marker.NewInstance(MarkerType.COMPUTED(), true));
870
871 featureToElementMap.forEach((feature, elements)->{
872 //aggregate categorical data
873 if(feature.isSupportsCategoricalData()){
874 CategoricalData aggregate = CategoricalData.NewInstance(feature);
875 elements.stream()
876 .filter(element->element instanceof CategoricalData)
877 .forEach(categoricalData->((CategoricalData)categoricalData).getStateData()
878 .forEach(stateData->aggregate.addStateData(stateData)));
879 description.addElement(aggregate);
880 }
881 //aggregate quantitative data
882 else if(feature.isSupportsQuantitativeData()){
883 QuantitativeData aggregate = QuantitativeData.NewInstance(feature);
884 elements.stream()
885 .filter(element->element instanceof QuantitativeData)
886 .forEach(categoricalData->((QuantitativeData)categoricalData).getStatisticalValues()
887 .forEach(statisticalValue->aggregate.addStatisticalValue(statisticalValue)));
888 description.addElement(aggregate);
889 }
890 });
891 result.setCdmEntity(taxon);
892 return result;
893 }
894
895 }