3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.cdm
.api
.service
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collection
;
15 import java
.util
.List
;
18 import java
.util
.UUID
;
20 import org
.apache
.commons
.lang
.StringUtils
;
21 import org
.apache
.log4j
.Logger
;
22 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
23 import org
.springframework
.stereotype
.Service
;
24 import org
.springframework
.transaction
.annotation
.Propagation
;
25 import org
.springframework
.transaction
.annotation
.Transactional
;
27 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
28 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
29 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
30 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
31 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
32 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
33 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
34 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
35 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
36 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
37 import eu
.etaxonomy
.cdm
.model
.description
.FeatureTree
;
38 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTermBase
;
39 import eu
.etaxonomy
.cdm
.model
.description
.Scope
;
40 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
41 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
42 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
43 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
44 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
45 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
46 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
47 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
48 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ITermVocabularyDao
;
49 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IDescriptionDao
;
50 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IDescriptionElementDao
;
51 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IFeatureDao
;
52 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IFeatureNodeDao
;
53 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IFeatureTreeDao
;
54 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IStatisticalMeasurementValueDao
;
55 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
63 @Transactional(readOnly
= true, propagation
= Propagation
.SUPPORTS
)
64 public class DescriptionServiceImpl
extends IdentifiableServiceBase
<DescriptionBase
,IDescriptionDao
> implements IDescriptionService
{
66 private static final Logger logger
= Logger
.getLogger(DescriptionServiceImpl
.class);
68 protected IDescriptionElementDao descriptionElementDao
;
69 protected IFeatureTreeDao featureTreeDao
;
70 protected IFeatureNodeDao featureNodeDao
;
71 protected IFeatureDao featureDao
;
72 protected ITermVocabularyDao vocabularyDao
;
73 protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao
;
74 private NaturalLanguageGenerator naturalLanguageGenerator
;
77 protected void setFeatureTreeDao(IFeatureTreeDao featureTreeDao
) {
78 this.featureTreeDao
= featureTreeDao
;
82 protected void setFeatureNodeDao(IFeatureNodeDao featureNodeDao
) {
83 this.featureNodeDao
= featureNodeDao
;
87 protected void setFeatureDao(IFeatureDao featureDao
) {
88 this.featureDao
= featureDao
;
92 protected void setVocabularyDao(ITermVocabularyDao vocabularyDao
) {
93 this.vocabularyDao
= vocabularyDao
;
97 protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao
) {
98 this.statisticalMeasurementValueDao
= statisticalMeasurementValueDao
;
102 protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao
) {
103 this.descriptionElementDao
= descriptionElementDao
;
107 protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator
) {
108 this.naturalLanguageGenerator
= naturalLanguageGenerator
;
114 public DescriptionServiceImpl() {
115 logger
.debug("Load DescriptionService Bean");
119 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache()
122 public void updateTitleCache() {
123 Class
<DescriptionBase
> clazz
= DescriptionBase
.class;
124 super.updateTitleCache(clazz
, null, null);
127 public TermVocabulary
<Feature
> getDefaultFeatureVocabulary(){
128 String uuidFeature
= "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
129 UUID featureUuid
= UUID
.fromString(uuidFeature
);
130 return (TermVocabulary
)vocabularyDao
.findByUuid(featureUuid
);
134 protected void setDao(IDescriptionDao dao
) {
138 public int count(Class
<?
extends DescriptionBase
> type
, Boolean hasImages
, Boolean hasText
,Set
<Feature
> feature
) {
139 return dao
.countDescriptions(type
, hasImages
, hasText
, feature
);
143 * FIXME Candidate for harmonization
144 * rename -> getElements
146 public Pager
<DescriptionElementBase
> getDescriptionElements(DescriptionBase description
,
147 Set
<Feature
> features
, Class
<?
extends DescriptionElementBase
> type
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
149 List
<DescriptionElementBase
> results
= listDescriptionElements(description
, features
, type
, pageSize
, pageNumber
, propertyPaths
);
150 return new DefaultPagerImpl
<DescriptionElementBase
>(pageNumber
, results
.size(), pageSize
, results
);
153 public List
<DescriptionElementBase
> listDescriptionElements(DescriptionBase description
,
154 Set
<Feature
> features
, Class
<?
extends DescriptionElementBase
> type
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
155 Integer numberOfResults
= dao
.countDescriptionElements(description
, features
, type
);
157 List
<DescriptionElementBase
> results
= new ArrayList
<DescriptionElementBase
>();
158 if(numberOfResults
> 0) { // no point checking again
159 results
= dao
.getDescriptionElements(description
, features
, type
, pageSize
, pageNumber
, propertyPaths
);
163 public Pager
<Annotation
> getDescriptionElementAnnotations(DescriptionElementBase annotatedObj
, MarkerType status
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
164 Integer numberOfResults
= descriptionElementDao
.countAnnotations(annotatedObj
, status
);
166 List
<Annotation
> results
= new ArrayList
<Annotation
>();
167 if(numberOfResults
> 0) { // no point checking again
168 results
= descriptionElementDao
.getAnnotations(annotatedObj
, status
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
171 return new DefaultPagerImpl
<Annotation
>(pageNumber
, numberOfResults
, pageSize
, results
);
176 public Pager
<Media
> getMedia(DescriptionElementBase descriptionElement
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
177 Integer numberOfResults
= descriptionElementDao
.countMedia(descriptionElement
);
179 List
<Media
> results
= new ArrayList
<Media
>();
180 if(numberOfResults
> 0) { // no point checking again
181 results
= descriptionElementDao
.getMedia(descriptionElement
, pageSize
, pageNumber
, propertyPaths
);
184 return new DefaultPagerImpl
<Media
>(pageNumber
, numberOfResults
, pageSize
, results
);
187 public Pager
<TaxonDescription
> getTaxonDescriptions(Taxon taxon
, Set
<Scope
> scopes
, Set
<NamedArea
> geographicalScope
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
188 Integer numberOfResults
= dao
.countTaxonDescriptions(taxon
, scopes
, geographicalScope
);
190 List
<TaxonDescription
> results
= new ArrayList
<TaxonDescription
>();
191 if(numberOfResults
> 0) { // no point checking again
192 results
= dao
.getTaxonDescriptions(taxon
, scopes
, geographicalScope
, pageSize
, pageNumber
, propertyPaths
);
195 return new DefaultPagerImpl
<TaxonDescription
>(pageNumber
, numberOfResults
, pageSize
, results
);
198 public List
<TaxonDescription
> listTaxonDescriptions(Taxon taxon
, Set
<Scope
> scopes
, Set
<NamedArea
> geographicalScope
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
199 List
<TaxonDescription
> results
= dao
.getTaxonDescriptions(taxon
, scopes
, geographicalScope
, pageSize
, pageNumber
, propertyPaths
);
203 public DistributionTree
getOrderedDistributions(
204 Set
<TaxonDescription
> taxonDescriptions
,
205 Set
<NamedAreaLevel
> omitLevels
,
206 List
<String
> propertyPaths
){
208 DistributionTree tree
= new DistributionTree();
209 List
<Distribution
> distList
= new ArrayList
<Distribution
>();
211 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
212 taxonDescription
= (TaxonDescription
) dao
.load(taxonDescription
.getUuid(), propertyPaths
);
213 Set
<DescriptionElementBase
> elements
= taxonDescription
.getElements();
214 for (DescriptionElementBase element
: elements
) {
215 if (element
.isInstanceOf(Distribution
.class)) {
216 Distribution distribution
= (Distribution
) element
;
217 if(distribution
.getArea() != null){
218 distList
.add(distribution
);
225 tree
.merge(distList
, omitLevels
);
230 public Pager
<TaxonNameDescription
> getTaxonNameDescriptions(TaxonNameBase name
, Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
) {
231 Integer numberOfResults
= dao
.countTaxonNameDescriptions(name
);
233 List
<TaxonNameDescription
> results
= new ArrayList
<TaxonNameDescription
>();
234 if(numberOfResults
> 0) { // no point checking again
235 results
= dao
.getTaxonNameDescriptions(name
, pageSize
, pageNumber
,propertyPaths
);
238 return new DefaultPagerImpl
<TaxonNameDescription
>(pageNumber
, numberOfResults
, pageSize
, results
);
242 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
) {
243 Integer numberOfResults
= dao
.countDescriptions(type
, hasImages
, hasText
, feature
);
245 List
<DescriptionBase
> results
= new ArrayList
<DescriptionBase
>();
246 if(numberOfResults
> 0) { // no point checking again
247 results
= dao
.listDescriptions(type
, hasImages
, hasText
, feature
, pageSize
, pageNumber
,orderHints
,propertyPaths
);
250 return new DefaultPagerImpl
<DescriptionBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
254 * FIXME Candidate for harmonization
255 * Rename: searchByDistribution
257 public Pager
<TaxonDescription
> searchDescriptionByDistribution(Set
<NamedArea
> namedAreas
, PresenceAbsenceTermBase presence
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
258 Integer numberOfResults
= dao
.countDescriptionByDistribution(namedAreas
, presence
);
260 List
<TaxonDescription
> results
= new ArrayList
<TaxonDescription
>();
261 if(numberOfResults
> 0) { // no point checking again
262 results
= dao
.searchDescriptionByDistribution(namedAreas
, presence
, pageSize
, pageNumber
,orderHints
,propertyPaths
);
265 return new DefaultPagerImpl
<TaxonDescription
>(pageNumber
, numberOfResults
, pageSize
, results
);
269 * FIXME Candidate for harmonization
270 * move: descriptionElementService.search
272 public Pager
<DescriptionElementBase
> searchElements(Class
<?
extends DescriptionElementBase
> clazz
, String queryString
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
273 Integer numberOfResults
= descriptionElementDao
.count(clazz
,queryString
);
275 List
<DescriptionElementBase
> results
= new ArrayList
<DescriptionElementBase
>();
276 if(numberOfResults
> 0) { // no point checking again
277 results
= descriptionElementDao
.search(clazz
, queryString
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
280 return new DefaultPagerImpl
<DescriptionElementBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
284 * FIXME Candidate for harmonization
285 * descriptionElementService.find
287 public DescriptionElementBase
getDescriptionElementByUuid(UUID uuid
) {
288 return descriptionElementDao
.findByUuid(uuid
);
292 * FIXME Candidate for harmonization
293 * descriptionElementService.load
295 public DescriptionElementBase
loadDescriptionElement(UUID uuid
, List
<String
> propertyPaths
) {
296 return descriptionElementDao
.load(uuid
, propertyPaths
);
300 * FIXME Candidate for harmonization
301 * descriptionElementService.save
303 @Transactional(readOnly
= false)
304 public UUID
saveDescriptionElement(DescriptionElementBase descriptionElement
) {
305 return descriptionElementDao
.save(descriptionElement
);
309 * FIXME Candidate for harmonization
310 * descriptionElementService.save
312 @Transactional(readOnly
= false)
313 public Map
<UUID
, DescriptionElementBase
> saveDescriptionElement(Collection
<DescriptionElementBase
> descriptionElements
) {
314 return descriptionElementDao
.saveAll(descriptionElements
);
318 * FIXME Candidate for harmonization
319 * descriptionElementService.delete
321 public UUID
deleteDescriptionElement(DescriptionElementBase descriptionElement
) {
322 return descriptionElementDao
.delete(descriptionElement
);
325 public TermVocabulary
<Feature
> getFeatureVocabulary(UUID uuid
) {
326 return (TermVocabulary
)vocabularyDao
.findByUuid(uuid
);
329 public List
<DescriptionElementBase
> getDescriptionElementsForTaxon(
330 Taxon taxon
, Set
<Feature
> features
,
331 Class
<?
extends DescriptionElementBase
> type
, Integer pageSize
,
332 Integer pageNumber
, List
<String
> propertyPaths
) {
333 return dao
.getDescriptionElementForTaxon(taxon
, features
, type
, pageSize
, pageNumber
, propertyPaths
);
336 public List
<DescriptionElementBase
> getDescriptionElementsForTaxon(
337 Taxon taxon
, FeatureTree featureTree
,
338 Class
<?
extends DescriptionElementBase
> type
, Integer pageSize
,
339 Integer pageNumber
, List
<String
> propertyPaths
) {
340 return dao
.getDescriptionElementForTaxon(taxon
, featureTree
.getDistinctFeatures(), type
, pageSize
, pageNumber
, propertyPaths
);
344 * @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)
347 public String
generateNaturalLanguageDescription(FeatureTree featureTree
,
348 TaxonDescription description
, List
<Language
> preferredLanguages
, String separator
) {
350 Language lang
= preferredLanguages
.size() > 0 ? preferredLanguages
.get(0) : Language
.DEFAULT();
352 description
= (TaxonDescription
)load(description
.getUuid());
353 featureTree
= featureTreeDao
.load(featureTree
.getUuid());
355 StringBuilder naturalLanguageDescription
= new StringBuilder();
357 if(description
.hasStructuredData()){
360 String lastCategory
= null;
361 String categorySeparator
= ". ";
363 List
<TextData
> textDataList
;
364 String naturalLanguageDescriptionText
= null;
366 boolean useMicroFormatQuantitativeDescriptionBuilder
= false;
368 if(useMicroFormatQuantitativeDescriptionBuilder
){
370 MicroFormatQuantitativeDescriptionBuilder micro
= new MicroFormatQuantitativeDescriptionBuilder();
371 naturalLanguageGenerator
.setQuantitativeDescriptionBuilder(micro
);
372 naturalLanguageDescriptionText
= naturalLanguageGenerator
.generateStringNaturalLanguageDescription(featureTree
, ((TaxonDescription
)description
), lang
);
375 naturalLanguageDescriptionText
= naturalLanguageGenerator
.generateStringNaturalLanguageDescription(
377 ((TaxonDescription
)description
),
381 return naturalLanguageDescriptionText
;
384 // boolean doItBetter = false;
386 // for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
387 // if(textData.getMultilanguageText().size() > 0){
389 // if (!textData.getFeature().equals(Feature.UNKNOWN())) {
390 // String featureLabel = textData.getFeature().getLabel(lang);
395 // * The code lines below are desinged to handle
396 // * a special case where as the feature label contains
397 // * hierarchical information on the features. This code
398 // * exist only as a base for discussion, and is not
399 // * intendet to be used in production.
401 // featureLabel = StringUtils.remove(featureLabel, '>');
403 // String[] labelTokens = StringUtils.split(featureLabel, '<');
404 // if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
405 // if(naturalLanguageDescription.length() > 0){
406 // naturalLanguageDescription.append(separator);
408 // naturalLanguageDescription.append(labelTokens[1]);
410 // if(naturalLanguageDescription.length() > 0){
411 // naturalLanguageDescription.append(categorySeparator);
413 // naturalLanguageDescription.append(StringUtils.join(labelTokens));
415 // lastCategory = labelTokens[0];
416 // // end of demo code
418 // if(naturalLanguageDescription.length() > 0){
419 // naturalLanguageDescription.append(separator);
421 // naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
424 // if(naturalLanguageDescription.length() > 0){
425 // naturalLanguageDescription.append(separator);
428 // String text = textData.getMultilanguageText().values().iterator().next().getText();
429 // naturalLanguageDescription.append(text);
435 return naturalLanguageDescription
.toString();
439 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#hasStructuredData(eu.etaxonomy.cdm.model.description.DescriptionBase)
442 public boolean hasStructuredData(DescriptionBase
<?
> description
) {
443 return load(description
.getUuid()).hasStructuredData();