remove imports
[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.HashSet;
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.common.IProgressMonitor;
30 import eu.etaxonomy.cdm.model.common.Annotation;
31 import eu.etaxonomy.cdm.model.common.Language;
32 import eu.etaxonomy.cdm.model.common.MarkerType;
33 import eu.etaxonomy.cdm.model.common.TermVocabulary;
34 import eu.etaxonomy.cdm.model.description.DescriptionBase;
35 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
36 import eu.etaxonomy.cdm.model.description.Distribution;
37 import eu.etaxonomy.cdm.model.description.Feature;
38 import eu.etaxonomy.cdm.model.description.FeatureTree;
39 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTermBase;
40 import eu.etaxonomy.cdm.model.description.Scope;
41 import eu.etaxonomy.cdm.model.description.TaxonDescription;
42 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
43 import eu.etaxonomy.cdm.model.description.TextData;
44 import eu.etaxonomy.cdm.model.location.NamedArea;
45 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
46 import eu.etaxonomy.cdm.model.media.Media;
47 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
48 import eu.etaxonomy.cdm.model.taxon.Taxon;
49 import eu.etaxonomy.cdm.persistence.dao.common.ITermVocabularyDao;
50 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
51 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionElementDao;
52 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureDao;
53 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureNodeDao;
54 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureTreeDao;
55 import eu.etaxonomy.cdm.persistence.dao.description.IStatisticalMeasurementValueDao;
56 import eu.etaxonomy.cdm.persistence.query.OrderHint;
57 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
58
59 /**
60 * @author a.mueller
61 * @created 24.06.2008
62 * @version 1.0
63 */
64 @Service
65 @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
66 public class DescriptionServiceImpl extends IdentifiableServiceBase<DescriptionBase,IDescriptionDao> implements IDescriptionService {
67
68 private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
69
70 protected IDescriptionElementDao descriptionElementDao;
71 protected IFeatureTreeDao featureTreeDao;
72 protected IFeatureNodeDao featureNodeDao;
73 protected IFeatureDao featureDao;
74 protected ITermVocabularyDao vocabularyDao;
75 protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
76 //TODO change to Interface
77 private NaturalLanguageGenerator naturalLanguageGenerator;
78
79 @Autowired
80 protected void setFeatureTreeDao(IFeatureTreeDao featureTreeDao) {
81 this.featureTreeDao = featureTreeDao;
82 }
83
84 @Autowired
85 protected void setFeatureNodeDao(IFeatureNodeDao featureNodeDao) {
86 this.featureNodeDao = featureNodeDao;
87 }
88
89 @Autowired
90 protected void setFeatureDao(IFeatureDao featureDao) {
91 this.featureDao = featureDao;
92 }
93
94 @Autowired
95 protected void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
96 this.vocabularyDao = vocabularyDao;
97 }
98
99 @Autowired
100 protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao) {
101 this.statisticalMeasurementValueDao = statisticalMeasurementValueDao;
102 }
103
104 @Autowired
105 protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao) {
106 this.descriptionElementDao = descriptionElementDao;
107 }
108
109 @Autowired
110 protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator) {
111 this.naturalLanguageGenerator = naturalLanguageGenerator;
112 }
113
114 /**
115 *
116 */
117 public DescriptionServiceImpl() {
118 logger.debug("Load DescriptionService Bean");
119 }
120
121
122
123 /* (non-Javadoc)
124 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
125 */
126 @Override
127 public void updateTitleCache(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
128 if (clazz == null){
129 clazz = DescriptionBase.class;
130 }
131 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
132 }
133
134
135 public TermVocabulary<Feature> getDefaultFeatureVocabulary(){
136 String uuidFeature = "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
137 UUID featureUuid = UUID.fromString(uuidFeature);
138 return (TermVocabulary)vocabularyDao.findByUuid(featureUuid);
139 }
140
141 @Autowired
142 protected void setDao(IDescriptionDao dao) {
143 this.dao = dao;
144 }
145
146 public int count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
147 return dao.countDescriptions(type, hasImages, hasText, feature);
148 }
149
150 /**
151 * FIXME Candidate for harmonization
152 * rename -> getElements
153 */
154 public Pager<DescriptionElementBase> getDescriptionElements(DescriptionBase description,
155 Set<Feature> features, Class<? extends DescriptionElementBase> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
156
157 List<DescriptionElementBase> results = listDescriptionElements(description, features, type, pageSize, pageNumber, propertyPaths);
158 return new DefaultPagerImpl<DescriptionElementBase>(pageNumber, results.size(), pageSize, results);
159 }
160
161 public List<DescriptionElementBase> listDescriptionElements(DescriptionBase description,
162 Set<Feature> features, Class<? extends DescriptionElementBase> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
163 Integer numberOfResults = dao.countDescriptionElements(description, features, type);
164
165 List<DescriptionElementBase> results = new ArrayList<DescriptionElementBase>();
166 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
167 results = dao.getDescriptionElements(description, features, type, pageSize, pageNumber, propertyPaths);
168 }
169 return results;
170 }
171
172 public Pager<Annotation> getDescriptionElementAnnotations(DescriptionElementBase annotatedObj, MarkerType status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
173 Integer numberOfResults = descriptionElementDao.countAnnotations(annotatedObj, status);
174
175 List<Annotation> results = new ArrayList<Annotation>();
176 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
177 results = descriptionElementDao.getAnnotations(annotatedObj, status, pageSize, pageNumber, orderHints, propertyPaths);
178 }
179
180 return new DefaultPagerImpl<Annotation>(pageNumber, numberOfResults, pageSize, results);
181 }
182
183
184
185 public Pager<Media> getMedia(DescriptionElementBase descriptionElement, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
186 Integer numberOfResults = descriptionElementDao.countMedia(descriptionElement);
187
188 List<Media> results = new ArrayList<Media>();
189 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
190 results = descriptionElementDao.getMedia(descriptionElement, pageSize, pageNumber, propertyPaths);
191 }
192
193 return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
194 }
195
196 public Pager<TaxonDescription> getTaxonDescriptions(Taxon taxon, Set<Scope> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
197 Integer numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope);
198
199 List<TaxonDescription> results = new ArrayList<TaxonDescription>();
200 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
201 results = dao.getTaxonDescriptions(taxon, scopes, geographicalScope, pageSize, pageNumber, propertyPaths);
202 }
203
204 return new DefaultPagerImpl<TaxonDescription>(pageNumber, numberOfResults, pageSize, results);
205 }
206
207 public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<Scope> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
208 List<TaxonDescription> results = dao.getTaxonDescriptions(taxon, scopes, geographicalScope, pageSize, pageNumber, propertyPaths);
209 return results;
210 }
211
212 public DistributionTree getOrderedDistributions(
213 Set<TaxonDescription> taxonDescriptions,
214 Set<NamedAreaLevel> omitLevels,
215 List<String> propertyPaths){
216
217 DistributionTree tree = new DistributionTree();
218 List<Distribution> distList = new ArrayList<Distribution>();
219
220 for (TaxonDescription taxonDescription : taxonDescriptions) {
221 taxonDescription = (TaxonDescription) dao.load(taxonDescription.getUuid(), propertyPaths);
222 Set<DescriptionElementBase> elements = taxonDescription.getElements();
223 for (DescriptionElementBase element : elements) {
224 if (element.isInstanceOf(Distribution.class)) {
225 Distribution distribution = (Distribution) element;
226 if(distribution.getArea() != null){
227 distList.add(distribution);
228 }
229 }
230 }
231 }
232
233 //ordering the areas
234 tree.merge(distList, omitLevels);
235 tree.sortChildren();
236 return tree;
237 }
238
239 public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonNameBase name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
240 Integer numberOfResults = dao.countTaxonNameDescriptions(name);
241
242 List<TaxonNameDescription> results = new ArrayList<TaxonNameDescription>();
243 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
244 results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
245 }
246
247 return new DefaultPagerImpl<TaxonNameDescription>(pageNumber, numberOfResults, pageSize, results);
248 }
249
250
251 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) {
252 Integer numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
253
254 List<DescriptionBase> results = new ArrayList<DescriptionBase>();
255 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
256 results = dao.listDescriptions(type, hasImages, hasText, feature, pageSize, pageNumber,orderHints,propertyPaths);
257 }
258
259 return new DefaultPagerImpl<DescriptionBase>(pageNumber, numberOfResults, pageSize, results);
260 }
261
262 /**
263 * FIXME Candidate for harmonization
264 * Rename: searchByDistribution
265 */
266 public Pager<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTermBase presence, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
267 Integer numberOfResults = dao.countDescriptionByDistribution(namedAreas, presence);
268
269 List<TaxonDescription> results = new ArrayList<TaxonDescription>();
270 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
271 results = dao.searchDescriptionByDistribution(namedAreas, presence, pageSize, pageNumber,orderHints,propertyPaths);
272 }
273
274 return new DefaultPagerImpl<TaxonDescription>(pageNumber, numberOfResults, pageSize, results);
275 }
276
277 /**
278 * FIXME Candidate for harmonization
279 * move: descriptionElementService.search
280 */
281 public Pager<DescriptionElementBase> searchElements(Class<? extends DescriptionElementBase> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
282 Integer numberOfResults = descriptionElementDao.count(clazz,queryString);
283
284 List<DescriptionElementBase> results = new ArrayList<DescriptionElementBase>();
285 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
286 results = descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
287 }
288
289 return new DefaultPagerImpl<DescriptionElementBase>(pageNumber, numberOfResults, pageSize, results);
290 }
291
292 /**
293 * FIXME Candidate for harmonization
294 * descriptionElementService.find
295 */
296 public DescriptionElementBase getDescriptionElementByUuid(UUID uuid) {
297 return descriptionElementDao.findByUuid(uuid);
298 }
299
300 /**
301 * FIXME Candidate for harmonization
302 * descriptionElementService.load
303 */
304 public DescriptionElementBase loadDescriptionElement(UUID uuid, List<String> propertyPaths) {
305 return descriptionElementDao.load(uuid, propertyPaths);
306 }
307
308 /**
309 * FIXME Candidate for harmonization
310 * descriptionElementService.save
311 */
312 @Transactional(readOnly = false)
313 public UUID saveDescriptionElement(DescriptionElementBase descriptionElement) {
314 return descriptionElementDao.save(descriptionElement);
315 }
316
317 /**
318 * FIXME Candidate for harmonization
319 * descriptionElementService.save
320 */
321 @Transactional(readOnly = false)
322 public Map<UUID, DescriptionElementBase> saveDescriptionElement(Collection<DescriptionElementBase> descriptionElements) {
323 return descriptionElementDao.saveAll(descriptionElements);
324 }
325
326 /**
327 * FIXME Candidate for harmonization
328 * descriptionElementService.delete
329 */
330 public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
331 return descriptionElementDao.delete(descriptionElement);
332 }
333
334 public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
335 return (TermVocabulary)vocabularyDao.findByUuid(uuid);
336 }
337
338 public <T extends DescriptionElementBase> List<T> getDescriptionElementsForTaxon(
339 Taxon taxon, Set<Feature> features,
340 Class<? extends T> type, Integer pageSize,
341 Integer pageNumber, List<String> propertyPaths) {
342 //FIXME remove cast
343 return (List<T>) dao.getDescriptionElementForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
344 }
345
346 public List<DescriptionElementBase> getDescriptionElementsForTaxon(
347 Taxon taxon, FeatureTree featureTree,
348 Class<? extends DescriptionElementBase> type, Integer pageSize,
349 Integer pageNumber, List<String> propertyPaths) {
350 //FIXME remove cast
351 return (List<DescriptionElementBase>) dao.getDescriptionElementForTaxon(taxon, featureTree.getDistinctFeatures(), type, pageSize, pageNumber, propertyPaths);
352 }
353
354 /* (non-Javadoc)
355 * @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)
356 */
357 @Override
358 public String generateNaturalLanguageDescription(FeatureTree featureTree,
359 TaxonDescription description, List<Language> preferredLanguages, String separator) {
360
361 Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
362
363 description = (TaxonDescription)load(description.getUuid());
364 featureTree = featureTreeDao.load(featureTree.getUuid());
365
366 StringBuilder naturalLanguageDescription = new StringBuilder();
367
368 if(description.hasStructuredData()){
369
370
371 String lastCategory = null;
372 String categorySeparator = ". ";
373
374 List<TextData> textDataList;
375 TextData naturalLanguageDescriptionText = null;
376
377 boolean useMicroFormatQuantitativeDescriptionBuilder = false;
378
379 if(useMicroFormatQuantitativeDescriptionBuilder){
380
381 MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
382 naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
383 naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, ((TaxonDescription)description), lang);
384
385 } else {
386
387 naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
388 featureTree,
389 ((TaxonDescription)description),
390 lang);
391 }
392
393 return naturalLanguageDescriptionText.getText(lang);
394
395 //
396 // boolean doItBetter = false;
397 //
398 // for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
399 // if(textData.getMultilanguageText().size() > 0){
400 //
401 // if (!textData.getFeature().equals(Feature.UNKNOWN())) {
402 // String featureLabel = textData.getFeature().getLabel(lang);
403 //
404 // if(doItBetter){
405 // /*
406 // * WARNING
407 // * The code lines below are desinged to handle
408 // * a special case where as the feature label contains
409 // * hierarchical information on the features. This code
410 // * exist only as a base for discussion, and is not
411 // * intendet to be used in production.
412 // */
413 // featureLabel = StringUtils.remove(featureLabel, '>');
414 //
415 // String[] labelTokens = StringUtils.split(featureLabel, '<');
416 // if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
417 // if(naturalLanguageDescription.length() > 0){
418 // naturalLanguageDescription.append(separator);
419 // }
420 // naturalLanguageDescription.append(labelTokens[1]);
421 // } else {
422 // if(naturalLanguageDescription.length() > 0){
423 // naturalLanguageDescription.append(categorySeparator);
424 // }
425 // naturalLanguageDescription.append(StringUtils.join(labelTokens));
426 // }
427 // lastCategory = labelTokens[0];
428 // // end of demo code
429 // } else {
430 // if(naturalLanguageDescription.length() > 0){
431 // naturalLanguageDescription.append(separator);
432 // }
433 // naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
434 // }
435 // } else {
436 // if(naturalLanguageDescription.length() > 0){
437 // naturalLanguageDescription.append(separator);
438 // }
439 // }
440 // String text = textData.getMultilanguageText().values().iterator().next().getText();
441 // naturalLanguageDescription.append(text);
442 //
443 // }
444 // }
445
446 }
447 return naturalLanguageDescription.toString();
448 }
449
450 /* (non-Javadoc)
451 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#hasStructuredData(eu.etaxonomy.cdm.model.description.DescriptionBase)
452 */
453 @Override
454 public boolean hasStructuredData(DescriptionBase<?> description) {
455 return load(description.getUuid()).hasStructuredData();
456 }
457
458
459 /* (non-Javadoc)
460 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#moveDescriptionElementsToDescription(java.util.Collection, eu.etaxonomy.cdm.model.description.DescriptionBase, boolean)
461 */
462 @Override
463 public void moveDescriptionElementsToDescription(Collection<DescriptionElementBase> descriptionElements,
464 DescriptionBase targetDescription, boolean isCopy) {
465
466 if (descriptionElements.isEmpty() ){
467 return ;
468 }
469
470 if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
471 //if the descriptionElements collection is the elements set of a description, put it in a separate set before to avoid concurrent modification exceptions
472 descriptionElements = new HashSet<DescriptionElementBase>(descriptionElements);
473 // descriptionElementsTmp.addAll(descriptionElements);
474 // descriptionElements = descriptionElementsTmp;
475 }
476 for (DescriptionElementBase element : descriptionElements){
477 DescriptionBase description = element.getInDescription();
478 try {
479 DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
480 targetDescription.addElement(newElement);
481 } catch (CloneNotSupportedException e) {
482 new RuntimeException ("Clone not yet implemented for class " + element.getClass().getName(), e);
483 }
484 if (! isCopy){
485 description.removeElement(element);
486 }
487
488 }
489 }
490
491 }