cdmlib 2.5
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DescriptionServiceImpl.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
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.
9 */
10
11 package eu.etaxonomy.cdm.api.service;
12
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.UUID;
19
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;
26
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;
56
57 /**
58 * @author a.mueller
59 * @created 24.06.2008
60 * @version 1.0
61 */
62 @Service
63 @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
64 public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionBase,IDescriptionDao> implements IDescriptionService {
65
66 private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
67
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;
75
76 @Autowired
77 protected void setFeatureTreeDao(IFeatureTreeDao featureTreeDao) {
78 this.featureTreeDao = featureTreeDao;
79 }
80
81 @Autowired
82 protected void setFeatureNodeDao(IFeatureNodeDao featureNodeDao) {
83 this.featureNodeDao = featureNodeDao;
84 }
85
86 @Autowired
87 protected void setFeatureDao(IFeatureDao featureDao) {
88 this.featureDao = featureDao;
89 }
90
91 @Autowired
92 protected void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
93 this.vocabularyDao = vocabularyDao;
94 }
95
96 @Autowired
97 protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao) {
98 this.statisticalMeasurementValueDao = statisticalMeasurementValueDao;
99 }
100
101 @Autowired
102 protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao) {
103 this.descriptionElementDao = descriptionElementDao;
104 }
105
106 @Autowired
107 protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator) {
108 this.naturalLanguageGenerator = naturalLanguageGenerator;
109 }
110
111 /**
112 *
113 */
114 public DescriptionServiceImpl() {
115 logger.debug("Load DescriptionService Bean");
116 }
117
118 /* (non-Javadoc)
119 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache()
120 */
121 @Override
122 public void updateTitleCache() {
123 Class<DescriptionBase> clazz = DescriptionBase.class;
124 super.updateTitleCache(clazz, null, null);
125 }
126
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);
131 }
132
133 @Autowired
134 protected void setDao(IDescriptionDao dao) {
135 this.dao = dao;
136 }
137
138 public int count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
139 return dao.countDescriptions(type, hasImages, hasText, feature);
140 }
141
142 /**
143 * FIXME Candidate for harmonization
144 * rename -> getElements
145 */
146 public Pager<DescriptionElementBase> getDescriptionElements(DescriptionBase description,
147 Set<Feature> features, Class<? extends DescriptionElementBase> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
148
149 List<DescriptionElementBase> results = listDescriptionElements(description, features, type, pageSize, pageNumber, propertyPaths);
150 return new DefaultPagerImpl<DescriptionElementBase>(pageNumber, results.size(), pageSize, results);
151 }
152
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);
156
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);
160 }
161 return results;
162 }
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);
165
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);
169 }
170
171 return new DefaultPagerImpl<Annotation>(pageNumber, numberOfResults, pageSize, results);
172 }
173
174
175
176 public Pager<Media> getMedia(DescriptionElementBase descriptionElement, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
177 Integer numberOfResults = descriptionElementDao.countMedia(descriptionElement);
178
179 List<Media> results = new ArrayList<Media>();
180 if(numberOfResults > 0) { // no point checking again
181 results = descriptionElementDao.getMedia(descriptionElement, pageSize, pageNumber, propertyPaths);
182 }
183
184 return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
185 }
186
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);
189
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);
193 }
194
195 return new DefaultPagerImpl<TaxonDescription>(pageNumber, numberOfResults, pageSize, results);
196 }
197
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);
200 return results;
201 }
202
203 public DistributionTree getOrderedDistributions(
204 Set<TaxonDescription> taxonDescriptions,
205 Set<NamedAreaLevel> omitLevels,
206 List<String> propertyPaths){
207
208 DistributionTree tree = new DistributionTree();
209 List<Distribution> distList = new ArrayList<Distribution>();
210
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);
219 }
220 }
221 }
222 }
223
224 //ordering the areas
225 tree.merge(distList, omitLevels);
226 tree.sortChildren();
227 return tree;
228 }
229
230 public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonNameBase name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
231 Integer numberOfResults = dao.countTaxonNameDescriptions(name);
232
233 List<TaxonNameDescription> results = new ArrayList<TaxonNameDescription>();
234 if(numberOfResults > 0) { // no point checking again
235 results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
236 }
237
238 return new DefaultPagerImpl<TaxonNameDescription>(pageNumber, numberOfResults, pageSize, results);
239 }
240
241
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);
244
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);
248 }
249
250 return new DefaultPagerImpl<DescriptionBase>(pageNumber, numberOfResults, pageSize, results);
251 }
252
253 /**
254 * FIXME Candidate for harmonization
255 * Rename: searchByDistribution
256 */
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);
259
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);
263 }
264
265 return new DefaultPagerImpl<TaxonDescription>(pageNumber, numberOfResults, pageSize, results);
266 }
267
268 /**
269 * FIXME Candidate for harmonization
270 * move: descriptionElementService.search
271 */
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);
274
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);
278 }
279
280 return new DefaultPagerImpl<DescriptionElementBase>(pageNumber, numberOfResults, pageSize, results);
281 }
282
283 /**
284 * FIXME Candidate for harmonization
285 * descriptionElementService.find
286 */
287 public DescriptionElementBase getDescriptionElementByUuid(UUID uuid) {
288 return descriptionElementDao.findByUuid(uuid);
289 }
290
291 /**
292 * FIXME Candidate for harmonization
293 * descriptionElementService.load
294 */
295 public DescriptionElementBase loadDescriptionElement(UUID uuid, List<String> propertyPaths) {
296 return descriptionElementDao.load(uuid, propertyPaths);
297 }
298
299 /**
300 * FIXME Candidate for harmonization
301 * descriptionElementService.save
302 */
303 @Transactional(readOnly = false)
304 public UUID saveDescriptionElement(DescriptionElementBase descriptionElement) {
305 return descriptionElementDao.save(descriptionElement);
306 }
307
308 /**
309 * FIXME Candidate for harmonization
310 * descriptionElementService.save
311 */
312 @Transactional(readOnly = false)
313 public Map<UUID, DescriptionElementBase> saveDescriptionElement(Collection<DescriptionElementBase> descriptionElements) {
314 return descriptionElementDao.saveAll(descriptionElements);
315 }
316
317 /**
318 * FIXME Candidate for harmonization
319 * descriptionElementService.delete
320 */
321 public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
322 return descriptionElementDao.delete(descriptionElement);
323 }
324
325 public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
326 return (TermVocabulary)vocabularyDao.findByUuid(uuid);
327 }
328
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);
334 }
335
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);
341 }
342
343 /* (non-Javadoc)
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)
345 */
346 @Override
347 public String generateNaturalLanguageDescription(FeatureTree featureTree,
348 TaxonDescription description, List<Language> preferredLanguages, String separator) {
349
350 Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
351
352 description = (TaxonDescription)load(description.getUuid());
353 featureTree = featureTreeDao.load(featureTree.getUuid());
354
355 StringBuilder naturalLanguageDescription = new StringBuilder();
356
357 if(description.hasStructuredData()){
358
359
360 String lastCategory = null;
361 String categorySeparator = ". ";
362
363 List<TextData> textDataList;
364 String naturalLanguageDescriptionText = null;
365
366 boolean useMicroFormatQuantitativeDescriptionBuilder = false;
367
368 if(useMicroFormatQuantitativeDescriptionBuilder){
369
370 MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
371 naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
372 naturalLanguageDescriptionText = naturalLanguageGenerator.generateStringNaturalLanguageDescription(featureTree, ((TaxonDescription)description), lang);
373
374 } else {
375 naturalLanguageDescriptionText = naturalLanguageGenerator.generateStringNaturalLanguageDescription(
376 featureTree,
377 ((TaxonDescription)description),
378 lang);
379 }
380
381 return naturalLanguageDescriptionText;
382
383 //
384 // boolean doItBetter = false;
385 //
386 // for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
387 // if(textData.getMultilanguageText().size() > 0){
388 //
389 // if (!textData.getFeature().equals(Feature.UNKNOWN())) {
390 // String featureLabel = textData.getFeature().getLabel(lang);
391 //
392 // if(doItBetter){
393 // /*
394 // * WARNING
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.
400 // */
401 // featureLabel = StringUtils.remove(featureLabel, '>');
402 //
403 // String[] labelTokens = StringUtils.split(featureLabel, '<');
404 // if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
405 // if(naturalLanguageDescription.length() > 0){
406 // naturalLanguageDescription.append(separator);
407 // }
408 // naturalLanguageDescription.append(labelTokens[1]);
409 // } else {
410 // if(naturalLanguageDescription.length() > 0){
411 // naturalLanguageDescription.append(categorySeparator);
412 // }
413 // naturalLanguageDescription.append(StringUtils.join(labelTokens));
414 // }
415 // lastCategory = labelTokens[0];
416 // // end of demo code
417 // } else {
418 // if(naturalLanguageDescription.length() > 0){
419 // naturalLanguageDescription.append(separator);
420 // }
421 // naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
422 // }
423 // } else {
424 // if(naturalLanguageDescription.length() > 0){
425 // naturalLanguageDescription.append(separator);
426 // }
427 // }
428 // String text = textData.getMultilanguageText().values().iterator().next().getText();
429 // naturalLanguageDescription.append(text);
430 //
431 // }
432 // }
433
434 }
435 return naturalLanguageDescription.toString();
436 }
437
438 /* (non-Javadoc)
439 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#hasStructuredData(eu.etaxonomy.cdm.model.description.DescriptionBase)
440 */
441 @Override
442 public boolean hasStructuredData(DescriptionBase<?> description) {
443 return load(description.getUuid()).hasStructuredData();
444 }
445 }