2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.api
.service
;
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
;
21 import java
.util
.UUID
;
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
;
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
;
83 * @author a.kohlbecker
88 @Transactional(readOnly
= true)
89 public class DescriptionServiceImpl
90 extends IdentifiableServiceBase
<DescriptionBase
,IDescriptionDao
>
91 implements IDescriptionService
{
93 private static final Logger logger
= Logger
.getLogger(DescriptionServiceImpl
.class);
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
;
105 //TODO change to Interface
106 private NaturalLanguageGenerator naturalLanguageGenerator
;
109 protected void setFeatureTreeDao(IFeatureTreeDao featureTreeDao
) {
110 this.featureTreeDao
= featureTreeDao
;
114 protected void setFeatureNodeDao(IFeatureNodeDao featureNodeDao
) {
115 this.featureNodeDao
= featureNodeDao
;
119 protected void setFeatureDao(IFeatureDao featureDao
) {
120 this.featureDao
= featureDao
;
124 protected void setVocabularyDao(ITermVocabularyDao vocabularyDao
) {
125 this.vocabularyDao
= vocabularyDao
;
129 protected void setDefinedTermDao(IDefinedTermDao definedTermDao
) {
130 this.definedTermDao
= definedTermDao
;
134 protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao
) {
135 this.statisticalMeasurementValueDao
= statisticalMeasurementValueDao
;
139 protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao
) {
140 this.descriptionElementDao
= descriptionElementDao
;
144 protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator
) {
145 this.naturalLanguageGenerator
= naturalLanguageGenerator
;
149 protected void setTaxonDao(ITaxonDao taxonDao
) {
150 this.taxonDao
= taxonDao
;
154 protected void setDataSetDao(IDescriptiveDataSetDao dataSetDao
) {
155 this.dataSetDao
= dataSetDao
;
161 public DescriptionServiceImpl() {
162 logger
.debug("Load DescriptionService Bean");
167 @Transactional(readOnly
= false)
168 public void updateTitleCache(Class
<?
extends DescriptionBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<DescriptionBase
> cacheStrategy
, IProgressMonitor monitor
) {
170 clazz
= DescriptionBase
.class;
172 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
177 public TermVocabulary
<Feature
> getDefaultFeatureVocabulary(){
178 String uuidFeature
= "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
179 UUID featureUuid
= UUID
.fromString(uuidFeature
);
180 return vocabularyDao
.findByUuid(featureUuid
);
185 protected void setDao(IDescriptionDao dao
) {
190 public long count(Class
<?
extends DescriptionBase
> type
, Boolean hasImages
, Boolean hasText
,Set
<Feature
> feature
) {
191 return dao
.countDescriptions(type
, hasImages
, hasText
, feature
);
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
) {
198 List
<T
> results
= listDescriptionElements(description
, descriptionType
, features
, type
, pageSize
, pageNumber
, propertyPaths
);
199 return new DefaultPagerImpl
<>(pageNumber
, results
.size(), pageSize
, results
);
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
);
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
) {
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
);
228 public <T
extends DescriptionElementBase
> List
<T
> listDescriptionElements(DescriptionBase description
,
229 Set
<Feature
> features
, Class
<T
> type
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
231 return listDescriptionElements(description
, null, features
, type
, pageSize
, pageNumber
, propertyPaths
);
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
);
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
);
243 return new DefaultPagerImpl
<>(pageNumber
, numberOfResults
, pageSize
, results
);
248 public Pager
<Media
> getMedia(DescriptionElementBase descriptionElement
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
249 Integer numberOfResults
= descriptionElementDao
.countMedia(descriptionElement
);
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
);
256 return new DefaultPagerImpl
<Media
>(pageNumber
, numberOfResults
, pageSize
, results
);
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
);
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
);
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
);
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
);
280 return new DefaultPagerImpl
<>(pageNumber
, numberOfResults
, pageSize
, results
);
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
);
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
);
296 public int countTaxonDescriptionMedia(UUID taxonUuid
, boolean limitToGalleries
, Set
<MarkerType
> markerTypes
){
297 return this.dao
.countTaxonDescriptionMedia(taxonUuid
, limitToGalleries
, markerTypes
);
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
){
309 List
<Distribution
> distList
= new ArrayList
<Distribution
>();
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());
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
);
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);
349 if (logger
.isDebugEnabled()){logger
.debug("filter tree for " + distList
.size() + " distributions ...");}
351 // filter distributions
352 Collection
<Distribution
> filteredDistributions
= DescriptionUtility
.filterDistributions(distList
, hiddenAreaMarkerTypes
, true, statusOrderPreference
, false);
354 distList
.addAll(filteredDistributions
);
356 return DescriptionUtility
.orderDistributions(definedTermDao
, omitLevels
, distList
, hiddenAreaMarkerTypes
, null);
361 public Pager
<TaxonNameDescription
> getTaxonNameDescriptions(TaxonName name
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
362 long numberOfResults
= dao
.countTaxonNameDescriptions(name
);
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
);
369 return new DefaultPagerImpl
<>(pageNumber
, numberOfResults
, pageSize
, results
);
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
);
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
);
383 return new DefaultPagerImpl
<>(pageNumber
, numberOfResults
, pageSize
, results
);
387 * FIXME Candidate for harmonization
388 * Rename: searchByDistribution
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
);
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
);
399 return new DefaultPagerImpl
<>(pageNumber
, numberOfResults
, pageSize
, results
);
403 * FIXME Candidate for harmonization
404 * move: descriptionElementService.search
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
);
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
);
415 return new DefaultPagerImpl
<>(pageNumber
, numberOfResults
, pageSize
, results
);
419 * FIXME Candidate for harmonization
420 * descriptionElementService.find
423 public DescriptionElementBase
getDescriptionElementByUuid(UUID uuid
) {
424 return descriptionElementDao
.findByUuid(uuid
);
428 * FIXME Candidate for harmonization
429 * descriptionElementService.load
432 public DescriptionElementBase
loadDescriptionElement(UUID uuid
, List
<String
> propertyPaths
) {
433 return descriptionElementDao
.load(uuid
, propertyPaths
);
437 * FIXME Candidate for harmonization
438 * descriptionElementService.save
441 @Transactional(readOnly
= false)
442 public UUID
saveDescriptionElement(DescriptionElementBase descriptionElement
) {
443 return descriptionElementDao
.save(descriptionElement
).getUuid();
447 * FIXME Candidate for harmonization
448 * descriptionElementService.save
451 @Transactional(readOnly
= false)
452 public Map
<UUID
, DescriptionElementBase
> saveDescriptionElement(Collection
<DescriptionElementBase
> descriptionElements
) {
453 return descriptionElementDao
.saveAll(descriptionElements
);
457 * FIXME Candidate for harmonization
458 * descriptionElementService.delete
461 public UUID
deleteDescriptionElement(DescriptionElementBase descriptionElement
) {
462 return descriptionElementDao
.delete(descriptionElement
);
467 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescriptionElement(java.util.UUID)
470 public UUID
deleteDescriptionElement(UUID descriptionElementUuid
) {
471 return deleteDescriptionElement(descriptionElementDao
.load(descriptionElementUuid
));
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
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
);
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
);
493 Set
<DescriptiveDataSet
> descriptiveDataSets
= description
.getDescriptiveDataSets();
494 for (Iterator
<DescriptiveDataSet
> iterator
= descriptiveDataSets
.iterator(); iterator
.hasNext();) {
495 iterator
.next().removeDescription(description
);
498 dao
.delete(description
);
499 deleteResult
.addDeletedObject(description
);
500 deleteResult
.setCdmEntity(description
);
508 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescription(java.util.UUID)
511 @Transactional(readOnly
= false)
512 public DeleteResult
deleteDescription(UUID descriptionUuid
) {
513 return deleteDescription(dao
.load(descriptionUuid
));
518 public TermVocabulary
<Feature
> getFeatureVocabulary(UUID uuid
) {
519 return vocabularyDao
.findByUuid(uuid
);
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
);
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
);
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
);
551 descriptionElements
= new ArrayList
<T
>(0);
553 if (logger
.isDebugEnabled()){logger
.debug(" service - DONE ...");}
554 return new DefaultPagerImpl
<T
>(pageNumber
, count
, pageSize
, descriptionElements
);
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)
562 public String
generateNaturalLanguageDescription(FeatureTree featureTree
,
563 TaxonDescription description
, List
<Language
> preferredLanguages
, String separator
) {
565 Language lang
= preferredLanguages
.size() > 0 ? preferredLanguages
.get(0) : Language
.DEFAULT();
567 description
= (TaxonDescription
)load(description
.getUuid());
568 featureTree
= featureTreeDao
.load(featureTree
.getUuid());
570 StringBuilder naturalLanguageDescription
= new StringBuilder();
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;
584 if(description
.hasStructuredData() && !isUseDescription
){
587 String lastCategory
= null;
588 String categorySeparator
= ". ";
590 List
<TextData
> textDataList
;
591 TextData naturalLanguageDescriptionText
= null;
593 boolean useMicroFormatQuantitativeDescriptionBuilder
= false;
595 if(useMicroFormatQuantitativeDescriptionBuilder
){
597 MicroFormatQuantitativeDescriptionBuilder micro
= new MicroFormatQuantitativeDescriptionBuilder();
598 naturalLanguageGenerator
.setQuantitativeDescriptionBuilder(micro
);
599 naturalLanguageDescriptionText
= naturalLanguageGenerator
.generateSingleTextData(featureTree
, (description
), lang
);
603 naturalLanguageDescriptionText
= naturalLanguageGenerator
.generateSingleTextData(
609 return naturalLanguageDescriptionText
.getText(lang
);
612 // boolean doItBetter = false;
614 // for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
615 // if(textData.getMultilanguageText().size() > 0){
617 // if (!textData.getFeature().equals(Feature.UNKNOWN())) {
618 // String featureLabel = textData.getFeature().getLabel(lang);
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.
629 // featureLabel = StringUtils.remove(featureLabel, '>');
631 // String[] labelTokens = StringUtils.split(featureLabel, '<');
632 // if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
633 // if(naturalLanguageDescription.length() > 0){
634 // naturalLanguageDescription.append(separator);
636 // naturalLanguageDescription.append(labelTokens[1]);
638 // if(naturalLanguageDescription.length() > 0){
639 // naturalLanguageDescription.append(categorySeparator);
641 // naturalLanguageDescription.append(StringUtils.join(labelTokens));
643 // lastCategory = labelTokens[0];
644 // // end of demo code
646 // if(naturalLanguageDescription.length() > 0){
647 // naturalLanguageDescription.append(separator);
649 // naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
652 // if(naturalLanguageDescription.length() > 0){
653 // naturalLanguageDescription.append(separator);
656 // String text = textData.getMultilanguageText().values().iterator().next().getText();
657 // naturalLanguageDescription.append(text);
663 else if (isUseDescription
) {
664 //AT: Left Blank in case we need to generate a Natural language text string.
666 return naturalLanguageDescription
.toString();
671 public boolean hasStructuredData(DescriptionBase
<?
> description
) {
672 return load(description
.getUuid()).hasStructuredData();
677 @Transactional(readOnly
= false)
678 public UpdateResult
moveDescriptionElementsToDescription(
679 Collection
<DescriptionElementBase
> descriptionElements
,
680 DescriptionBase targetDescription
,
683 UpdateResult result
= new UpdateResult();
684 if (descriptionElements
.isEmpty() ){
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;
694 for (DescriptionElementBase element
: descriptionElements
){
695 DescriptionBase
<?
> description
= element
.getInDescription();
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
);
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
);
711 dao
.delete(description
);
714 dao
.saveOrUpdate(description
);
715 result
.addUpdatedObject(description
);
721 dao
.saveOrUpdate(targetDescription
);
722 result
.addUpdatedObject(targetDescription
);
723 if (targetDescription
instanceof TaxonDescription
){
724 result
.addUpdatedObject(((TaxonDescription
)targetDescription
).getTaxon());
730 @Transactional(readOnly
= false)
731 public UpdateResult
moveDescriptionElementsToDescription(
732 Set
<UUID
> descriptionElementUUIDs
,
733 UUID targetDescriptionUuid
,
735 Set
<DescriptionElementBase
> descriptionElements
= new HashSet
<DescriptionElementBase
>();
736 for(UUID deUuid
: descriptionElementUUIDs
) {
737 descriptionElements
.add(descriptionElementDao
.load(deUuid
));
739 DescriptionBase targetDescription
= dao
.load(targetDescriptionUuid
);
741 return moveDescriptionElementsToDescription(descriptionElements
, targetDescription
, isCopy
);
745 @Transactional(readOnly
= false)
746 public UpdateResult
moveDescriptionElementsToDescription(
747 Set
<UUID
> descriptionElementUUIDs
,
748 UUID targetTaxonUuid
,
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
);
758 targetDescription
= dao
.save(targetDescription
);
759 Set
<DescriptionElementBase
> descriptionElements
= new HashSet
<DescriptionElementBase
>();
760 for(UUID deUuid
: descriptionElementUUIDs
) {
761 descriptionElements
.add(descriptionElementDao
.load(deUuid
));
764 return moveDescriptionElementsToDescription(descriptionElements
, targetDescription
, isCopy
);
768 public Pager
<TermDto
> pageNamedAreasInUse(boolean includeAllParents
, Integer pageSize
,
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
);
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
){
787 String moveMessage
= String
.format("Description moved from %s", sourceTaxon
);
788 if(description
.isProtectedTitleCache()){
789 String separator
= "";
790 if(!StringUtils
.isBlank(description
.getTitleCache())){
793 description
.setTitleCache(description
.getTitleCache() + separator
+ moveMessage
, true);
795 Annotation annotation
= Annotation
.NewInstance(moveMessage
, Language
.getDefaultLanguage());
796 annotation
.setAnnotationType(AnnotationType
.TECHNICAL());
797 description
.addAnnotation(annotation
);
798 targetTaxon
.addDescription(description
);
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
);
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);
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())){
825 description
.setTitleCache(description
.getTitleCache() + separator
+ moveMessage
, true);
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);
840 public UpdateResult
aggregateDescription(UUID taxonUuid
, Collection
<UUID
> descriptionUuids
, UUID descriptiveDataSet
) {
841 UpdateResult result
= new UpdateResult();
842 Map
<Feature
, List
<DescriptionElementBase
>> featureToElementMap
= new HashMap
<>();
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"));
851 Taxon taxon
= (Taxon
)taxonBase
;
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());
860 list
= new ArrayList
<>();
862 list
.add(descriptionElement
);
863 featureToElementMap
.put(descriptionElement
.getFeature(), list
);
867 TaxonDescription description
= TaxonDescription
.NewInstance(taxon
);
868 description
.setTitleCache("[Aggregation] "+dataSet
.getTitleCache(), true);
869 description
.addMarker(Marker
.NewInstance(MarkerType
.COMPUTED(), true));
871 featureToElementMap
.forEach((feature
, elements
)->{
872 //aggregate categorical data
873 if(feature
.isSupportsCategoricalData()){
874 CategoricalData aggregate
= CategoricalData
.NewInstance(feature
);
876 .filter(element
->element
instanceof CategoricalData
)
877 .forEach(categoricalData
->((CategoricalData
)categoricalData
).getStateData()
878 .forEach(stateData
->aggregate
.addStateData(stateData
)));
879 description
.addElement(aggregate
);
881 //aggregate quantitative data
882 else if(feature
.isSupportsQuantitativeData()){
883 QuantitativeData aggregate
= QuantitativeData
.NewInstance(feature
);
885 .filter(element
->element
instanceof QuantitativeData
)
886 .forEach(categoricalData
->((QuantitativeData
)categoricalData
).getStatisticalValues()
887 .forEach(statisticalValue
->aggregate
.addStatisticalValue(statisticalValue
)));
888 description
.addElement(aggregate
);
891 result
.setCdmEntity(taxon
);