86745f84243df3d6b3b1db3fc78bc0c1aca2dd4b
[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.Iterator;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.UUID;
20
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
164 public Pager<Annotation> getDescriptionElementAnnotations(DescriptionElementBase annotatedObj, MarkerType status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
165 Integer numberOfResults = descriptionElementDao.countAnnotations(annotatedObj, status);
166
167 List<Annotation> results = new ArrayList<Annotation>();
168 if(numberOfResults > 0) { // no point checking again
169 results = descriptionElementDao.getAnnotations(annotatedObj, status, pageSize, pageNumber, orderHints, propertyPaths);
170 }
171
172 return new DefaultPagerImpl<Annotation>(pageNumber, numberOfResults, pageSize, results);
173 }
174
175
176
177 public Pager<Media> getMedia(DescriptionElementBase descriptionElement, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
178 Integer numberOfResults = descriptionElementDao.countMedia(descriptionElement);
179
180 List<Media> results = new ArrayList<Media>();
181 if(numberOfResults > 0) { // no point checking again
182 results = descriptionElementDao.getMedia(descriptionElement, pageSize, pageNumber, propertyPaths);
183 }
184
185 return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
186 }
187
188 public Pager<TaxonDescription> getTaxonDescriptions(Taxon taxon, Set<Scope> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
189 Integer numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope);
190
191 List<TaxonDescription> results = new ArrayList<TaxonDescription>();
192 if(numberOfResults > 0) { // no point checking again
193 results = dao.getTaxonDescriptions(taxon, scopes, geographicalScope, pageSize, pageNumber, propertyPaths);
194 }
195
196 return new DefaultPagerImpl<TaxonDescription>(pageNumber, numberOfResults, pageSize, results);
197 }
198
199 public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<Scope> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
200 List<TaxonDescription> results = dao.getTaxonDescriptions(taxon, scopes, geographicalScope, pageSize, pageNumber, propertyPaths);
201 return results;
202 }
203
204 public DistributionTree getOrderedDistributions(
205 Set<TaxonDescription> taxonDescriptions,
206 Set<NamedAreaLevel> omitLevels,
207 List<String> propertyPaths){
208
209 DistributionTree tree = new DistributionTree();
210 List<Distribution> distList = new ArrayList<Distribution>();
211
212 for (TaxonDescription taxonDescription : taxonDescriptions) {
213 taxonDescription = (TaxonDescription) dao.load(taxonDescription.getUuid(), propertyPaths);
214 Set<DescriptionElementBase> elements = taxonDescription.getElements();
215 for (DescriptionElementBase element : elements) {
216 if (element.isInstanceOf(Distribution.class)) {
217 Distribution distribution = (Distribution) element;
218 if(distribution.getArea() != null){
219 distList.add(distribution);
220 }
221 }
222 }
223 }
224
225 //ordering the areas
226 tree.merge(distList, omitLevels);
227 tree.sortChildren();
228 return tree;
229 }
230
231 public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonNameBase name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
232 Integer numberOfResults = dao.countTaxonNameDescriptions(name);
233
234 List<TaxonNameDescription> results = new ArrayList<TaxonNameDescription>();
235 if(numberOfResults > 0) { // no point checking again
236 results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
237 }
238
239 return new DefaultPagerImpl<TaxonNameDescription>(pageNumber, numberOfResults, pageSize, results);
240 }
241
242
243 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) {
244 Integer numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
245
246 List<DescriptionBase> results = new ArrayList<DescriptionBase>();
247 if(numberOfResults > 0) { // no point checking again
248 results = dao.listDescriptions(type, hasImages, hasText, feature, pageSize, pageNumber,orderHints,propertyPaths);
249 }
250
251 return new DefaultPagerImpl<DescriptionBase>(pageNumber, numberOfResults, pageSize, results);
252 }
253
254 /**
255 * FIXME Candidate for harmonization
256 * Rename: searchByDistribution
257 */
258 public Pager<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTermBase presence, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
259 Integer numberOfResults = dao.countDescriptionByDistribution(namedAreas, presence);
260
261 List<TaxonDescription> results = new ArrayList<TaxonDescription>();
262 if(numberOfResults > 0) { // no point checking again
263 results = dao.searchDescriptionByDistribution(namedAreas, presence, pageSize, pageNumber,orderHints,propertyPaths);
264 }
265
266 return new DefaultPagerImpl<TaxonDescription>(pageNumber, numberOfResults, pageSize, results);
267 }
268
269 /**
270 * FIXME Candidate for harmonization
271 * move: descriptionElementService.search
272 */
273 public Pager<DescriptionElementBase> searchElements(Class<? extends DescriptionElementBase> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
274 Integer numberOfResults = descriptionElementDao.count(clazz,queryString);
275
276 List<DescriptionElementBase> results = new ArrayList<DescriptionElementBase>();
277 if(numberOfResults > 0) { // no point checking again
278 results = descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
279 }
280
281 return new DefaultPagerImpl<DescriptionElementBase>(pageNumber, numberOfResults, pageSize, results);
282 }
283
284 /**
285 * FIXME Candidate for harmonization
286 * descriptionElementService.find
287 */
288 public DescriptionElementBase getDescriptionElementByUuid(UUID uuid) {
289 return descriptionElementDao.findByUuid(uuid);
290 }
291
292 /**
293 * FIXME Candidate for harmonization
294 * descriptionElementService.load
295 */
296 public DescriptionElementBase loadDescriptionElement(UUID uuid, List<String> propertyPaths) {
297 return descriptionElementDao.load(uuid, propertyPaths);
298 }
299
300 /**
301 * FIXME Candidate for harmonization
302 * descriptionElementService.save
303 */
304 @Transactional(readOnly = false)
305 public UUID saveDescriptionElement(DescriptionElementBase descriptionElement) {
306 return descriptionElementDao.save(descriptionElement);
307 }
308
309 /**
310 * FIXME Candidate for harmonization
311 * descriptionElementService.save
312 */
313 @Transactional(readOnly = false)
314 public Map<UUID, DescriptionElementBase> saveDescriptionElement(Collection<DescriptionElementBase> descriptionElements) {
315 return descriptionElementDao.saveAll(descriptionElements);
316 }
317
318 /**
319 * FIXME Candidate for harmonization
320 * descriptionElementService.delete
321 */
322 public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
323 return descriptionElementDao.delete(descriptionElement);
324 }
325
326 public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
327 return (TermVocabulary)vocabularyDao.findByUuid(uuid);
328 }
329
330 public List<DescriptionElementBase> getDescriptionElementsForTaxon(
331 Taxon taxon, Set<Feature> features,
332 Class<? extends DescriptionElementBase> type, Integer pageSize,
333 Integer pageNumber, List<String> propertyPaths) {
334 //FIXME remove cast
335 return (List<DescriptionElementBase>) dao.getDescriptionElementForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
336 }
337
338 public List<DescriptionElementBase> getDescriptionElementsForTaxon(
339 Taxon taxon, FeatureTree featureTree,
340 Class<? extends DescriptionElementBase> type, Integer pageSize,
341 Integer pageNumber, List<String> propertyPaths) {
342 //FIXME remove cast
343 return (List<DescriptionElementBase>) dao.getDescriptionElementForTaxon(taxon, featureTree.getDistinctFeatures(), type, pageSize, pageNumber, propertyPaths);
344 }
345
346 /* (non-Javadoc)
347 * @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)
348 */
349 @Override
350 public String generateNaturalLanguageDescription(FeatureTree featureTree,
351 TaxonDescription description, List<Language> preferredLanguages, String separator) {
352
353 Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
354
355 description = (TaxonDescription)load(description.getUuid());
356 featureTree = featureTreeDao.load(featureTree.getUuid());
357
358 StringBuilder naturalLanguageDescription = new StringBuilder();
359
360 if(description.hasStructuredData()){
361
362
363 String lastCategory = null;
364 String categorySeparator = ". ";
365
366 List<TextData> textDataList;
367 String naturalLanguageDescriptionText = null;
368
369 boolean useMicroFormatQuantitativeDescriptionBuilder = false;
370
371 if(useMicroFormatQuantitativeDescriptionBuilder){
372
373 MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
374 naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
375 //FXIME commented because it lead to compile errors -> Maxime please fix
376 logger.error("naturalLanguageGenerator.generateStringNaturalLanguageDescription needs to be fixed");
377 // naturalLanguageDescriptionText = naturalLanguageGenerator.generateStringNaturalLanguageDescription(featureTree, ((TaxonDescription)description), lang);
378
379 } else {
380
381 //FXIME commented because it lead to compile errors -> Maxime please fix
382 logger.error("naturalLanguageGenerator.generateStringNaturalLanguageDescription needs to be fixed");
383 // naturalLanguageDescriptionText = naturalLanguageGenerator.generateStringNaturalLanguageDescription(
384 // featureTree,
385 // ((TaxonDescription)description),
386 // lang);
387 }
388
389 return naturalLanguageDescriptionText;
390
391 //
392 // boolean doItBetter = false;
393 //
394 // for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
395 // if(textData.getMultilanguageText().size() > 0){
396 //
397 // if (!textData.getFeature().equals(Feature.UNKNOWN())) {
398 // String featureLabel = textData.getFeature().getLabel(lang);
399 //
400 // if(doItBetter){
401 // /*
402 // * WARNING
403 // * The code lines below are desinged to handle
404 // * a special case where as the feature label contains
405 // * hierarchical information on the features. This code
406 // * exist only as a base for discussion, and is not
407 // * intendet to be used in production.
408 // */
409 // featureLabel = StringUtils.remove(featureLabel, '>');
410 //
411 // String[] labelTokens = StringUtils.split(featureLabel, '<');
412 // if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
413 // if(naturalLanguageDescription.length() > 0){
414 // naturalLanguageDescription.append(separator);
415 // }
416 // naturalLanguageDescription.append(labelTokens[1]);
417 // } else {
418 // if(naturalLanguageDescription.length() > 0){
419 // naturalLanguageDescription.append(categorySeparator);
420 // }
421 // naturalLanguageDescription.append(StringUtils.join(labelTokens));
422 // }
423 // lastCategory = labelTokens[0];
424 // // end of demo code
425 // } else {
426 // if(naturalLanguageDescription.length() > 0){
427 // naturalLanguageDescription.append(separator);
428 // }
429 // naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
430 // }
431 // } else {
432 // if(naturalLanguageDescription.length() > 0){
433 // naturalLanguageDescription.append(separator);
434 // }
435 // }
436 // String text = textData.getMultilanguageText().values().iterator().next().getText();
437 // naturalLanguageDescription.append(text);
438 //
439 // }
440 // }
441
442 }
443 return naturalLanguageDescription.toString();
444 }
445
446 /* (non-Javadoc)
447 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#hasStructuredData(eu.etaxonomy.cdm.model.description.DescriptionBase)
448 */
449 @Override
450 public boolean hasStructuredData(DescriptionBase<?> description) {
451 return load(description.getUuid()).hasStructuredData();
452 }
453
454 /* (non-Javadoc)
455 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#moveDescriptionElementsToDescription(java.util.Collection, eu.etaxonomy.cdm.model.description.DescriptionBase)
456 */
457 @Override
458 public void moveDescriptionElementsToDescription(Collection<DescriptionElementBase> descriptionElements,
459 DescriptionBase targetDescription, boolean isCopy) {
460 Iterator<DescriptionElementBase> iterator = descriptionElements.iterator();
461 while (iterator.hasNext()){
462 DescriptionElementBase elementToRemove = iterator.next();
463 if (! isCopy){
464 iterator.remove();
465 }else{
466 try {
467 elementToRemove = (DescriptionElementBase)elementToRemove.clone();
468 } catch (CloneNotSupportedException e) {
469 new RuntimeException ("Clone not yet implemented for class " + elementToRemove.getClass().getName(), e);
470 }
471 }
472 targetDescription.addElement(elementToRemove);
473 }
474 }
475
476 }