cleanup
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / DescriptionServiceImpl.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
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.
8 */
9
10 package eu.etaxonomy.cdm.api.service;
11
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.UUID;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.log4j.Logger;
24 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.stereotype.Service;
26 import org.springframework.transaction.annotation.Transactional;
27
28 import eu.etaxonomy.cdm.api.service.dto.TaxonDistributionDTO;
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.DescriptionBase;
44 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
45 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
46 import eu.etaxonomy.cdm.model.description.Distribution;
47 import eu.etaxonomy.cdm.model.description.Feature;
48 import eu.etaxonomy.cdm.model.description.FeatureTree;
49 import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
50 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
51 import eu.etaxonomy.cdm.model.description.TaxonDescription;
52 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
53 import eu.etaxonomy.cdm.model.description.TextData;
54 import eu.etaxonomy.cdm.model.location.NamedArea;
55 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
56 import eu.etaxonomy.cdm.model.media.Media;
57 import eu.etaxonomy.cdm.model.name.TaxonName;
58 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
59 import eu.etaxonomy.cdm.model.taxon.Taxon;
60 import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
61 import eu.etaxonomy.cdm.persistence.dao.common.ITermVocabularyDao;
62 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
63 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionElementDao;
64 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
65 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureDao;
66 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureNodeDao;
67 import eu.etaxonomy.cdm.persistence.dao.description.IFeatureTreeDao;
68 import eu.etaxonomy.cdm.persistence.dao.description.IStatisticalMeasurementValueDao;
69 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
70 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
71 import eu.etaxonomy.cdm.persistence.dto.MergeResult;
72 import eu.etaxonomy.cdm.persistence.dto.TermDto;
73 import eu.etaxonomy.cdm.persistence.query.OrderHint;
74 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
75
76 /**
77 * @author a.mueller
78 * @author a.kohlbecker
79 *
80 * @since 24.06.2008
81 *
82 */
83 @Service
84 @Transactional(readOnly = true)
85 public class DescriptionServiceImpl
86 extends IdentifiableServiceBase<DescriptionBase,IDescriptionDao>
87 implements IDescriptionService {
88
89 private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
90
91 protected IDescriptionElementDao descriptionElementDao;
92 protected IFeatureTreeDao featureTreeDao;
93 protected IDescriptiveDataSetDao descriptiveDataSetDao;
94 protected IFeatureNodeDao featureNodeDao;
95 protected IFeatureDao featureDao;
96 protected ITermVocabularyDao vocabularyDao;
97 protected IDefinedTermDao definedTermDao;
98 protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
99 protected ITaxonDao taxonDao;
100 protected ITaxonNodeDao taxonNodeDao;
101 protected IDescriptiveDataSetDao dataSetDao;
102
103 @Autowired
104 private IProgressMonitorService progressMonitorService;
105
106 //TODO change to Interface
107 private NaturalLanguageGenerator naturalLanguageGenerator;
108
109 @Autowired
110 protected void setFeatureTreeDao(IFeatureTreeDao featureTreeDao) {
111 this.featureTreeDao = featureTreeDao;
112 }
113
114 @Autowired
115 protected void setDescriptiveDataSetDao(IDescriptiveDataSetDao descriptiveDataSetDao) {
116 this.descriptiveDataSetDao = descriptiveDataSetDao;
117 }
118
119 @Autowired
120 protected void setFeatureNodeDao(IFeatureNodeDao featureNodeDao) {
121 this.featureNodeDao = featureNodeDao;
122 }
123
124 @Autowired
125 protected void setFeatureDao(IFeatureDao featureDao) {
126 this.featureDao = featureDao;
127 }
128
129 @Autowired
130 protected void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
131 this.vocabularyDao = vocabularyDao;
132 }
133
134 @Autowired
135 protected void setDefinedTermDao(IDefinedTermDao definedTermDao) {
136 this.definedTermDao = definedTermDao;
137 }
138
139 @Autowired
140 protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao) {
141 this.statisticalMeasurementValueDao = statisticalMeasurementValueDao;
142 }
143
144 @Autowired
145 protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao) {
146 this.descriptionElementDao = descriptionElementDao;
147 }
148
149 @Autowired
150 protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator) {
151 this.naturalLanguageGenerator = naturalLanguageGenerator;
152 }
153
154 @Autowired
155 protected void setTaxonDao(ITaxonDao taxonDao) {
156 this.taxonDao = taxonDao;
157 }
158
159 @Autowired
160 protected void setTaxonNodeDao(ITaxonNodeDao taxonNodeDao) {
161 this.taxonNodeDao = taxonNodeDao;
162 }
163
164 @Autowired
165 protected void setDataSetDao(IDescriptiveDataSetDao dataSetDao) {
166 this.dataSetDao = dataSetDao;
167 }
168
169 /**
170 *
171 */
172 public DescriptionServiceImpl() {
173 logger.debug("Load DescriptionService Bean");
174 }
175
176
177 @Override
178 @Transactional(readOnly = false)
179 public void updateTitleCache(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
180 if (clazz == null){
181 clazz = DescriptionBase.class;
182 }
183 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
184 }
185
186
187 @Override
188 public TermVocabulary<Feature> getDefaultFeatureVocabulary(){
189 String uuidFeature = "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
190 UUID featureUuid = UUID.fromString(uuidFeature);
191 return vocabularyDao.findByUuid(featureUuid);
192 }
193
194 @Override
195 @Autowired
196 protected void setDao(IDescriptionDao dao) {
197 this.dao = dao;
198 }
199
200 @Override
201 public long count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
202 return dao.countDescriptions(type, hasImages, hasText, feature);
203 }
204
205 @Override
206 public <T extends DescriptionElementBase> Pager<T> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
207 Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
208
209 List<T> results = listDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
210 return new DefaultPagerImpl<>(pageNumber, results.size(), pageSize, results);
211 }
212
213 @Override
214 @Deprecated
215 public <T extends DescriptionElementBase> Pager<T> getDescriptionElements(DescriptionBase description,
216 Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
217 return pageDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
218 }
219
220
221
222 @Override
223 public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
224 Class<? extends DescriptionBase> descriptionType, Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber,
225 List<String> propertyPaths) {
226
227 long numberOfResults = dao.countDescriptionElements(description, descriptionType, features, type);
228 List<T> results = new ArrayList<T>();
229 if(AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)) {
230 results = dao.getDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
231 }
232 return results;
233
234 }
235
236
237 @Override
238 @Deprecated
239 public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
240 Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
241
242 return listDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
243 }
244
245 @Override
246 public Pager<Annotation> getDescriptionElementAnnotations(DescriptionElementBase annotatedObj, MarkerType status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
247 long numberOfResults = descriptionElementDao.countAnnotations(annotatedObj, status);
248
249 List<Annotation> results = new ArrayList<>();
250 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
251 results = descriptionElementDao.getAnnotations(annotatedObj, status, pageSize, pageNumber, orderHints, propertyPaths);
252 }
253
254 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
255 }
256
257
258 @Override
259 public Pager<Media> getMedia(DescriptionElementBase descriptionElement, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
260 Integer numberOfResults = descriptionElementDao.countMedia(descriptionElement);
261
262 List<Media> results = new ArrayList<Media>();
263 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
264 results = descriptionElementDao.getMedia(descriptionElement, pageSize, pageNumber, propertyPaths);
265 }
266
267 return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
268 }
269
270 @Override
271 public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
272 Set<MarkerType> markerTypes = null;
273 return pageTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
274 }
275
276 @Override
277 public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
278 Set<MarkerType> markerTypes = null;
279 return listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
280 }
281
282 @Override
283 public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
284 long numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes);
285
286 List<TaxonDescription> results = new ArrayList<>();
287 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
288 results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
289 }
290
291 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
292 }
293
294 @Override
295 public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
296 List<TaxonDescription> results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, pageSize, pageNumber, propertyPaths);
297 return results;
298 }
299
300
301 @Override
302 public List<Media> listTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths){
303 return this.dao.listTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes, pageSize, pageNumber, propertyPaths);
304 }
305
306 @Override
307 public int countTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes){
308 return this.dao.countTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes);
309 }
310
311 @Override
312 @Deprecated
313 public DistributionTree getOrderedDistributions(
314 Set<TaxonDescription> taxonDescriptions,
315 boolean subAreaPreference,
316 boolean statusOrderPreference,
317 Set<MarkerType> hiddenAreaMarkerTypes,
318 Set<NamedAreaLevel> omitLevels, List<String> propertyPaths){
319
320 List<Distribution> distList = new ArrayList<Distribution>();
321
322 List<UUID> uuids = new ArrayList<UUID>();
323 for (TaxonDescription taxonDescription : taxonDescriptions) {
324 if (! taxonDescription.isImageGallery()){ //image galleries should not have descriptions, but better filter fully on DTYPE of description element
325 uuids.add(taxonDescription.getUuid());
326 }
327 }
328
329 List<DescriptionBase> desclist = dao.list(uuids, null, null, null, propertyPaths);
330 for (DescriptionBase desc : desclist) {
331 if (desc.isInstanceOf(TaxonDescription.class)){
332 Set<DescriptionElementBase> elements = desc.getElements();
333 for (DescriptionElementBase element : elements) {
334 if (element.isInstanceOf(Distribution.class)) {
335 Distribution distribution = (Distribution) element;
336 if(distribution.getArea() != null){
337 distList.add(distribution);
338 }
339 }
340 }
341 }
342 }
343
344 //old
345 // for (TaxonDescription taxonDescription : taxonDescriptions) {
346 // if (logger.isDebugEnabled()){ logger.debug("load taxon description " + taxonDescription.getUuid());}
347 // //TODO why not loading all description via .list ? This may improve performance
348 // taxonDescription = (TaxonDescription) dao.load(taxonDescription.getUuid(), propertyPaths);
349 // Set<DescriptionElementBase> elements = taxonDescription.getElements();
350 // for (DescriptionElementBase element : elements) {
351 // if (element.isInstanceOf(Distribution.class)) {
352 // Distribution distribution = (Distribution) element;
353 // if(distribution.getArea() != null){
354 // distList.add(distribution);
355 // }
356 // }
357 // }
358 // }
359
360 if (logger.isDebugEnabled()){logger.debug("filter tree for " + distList.size() + " distributions ...");}
361
362 // filter distributions
363 Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distList, hiddenAreaMarkerTypes, true, statusOrderPreference, false);
364 distList.clear();
365 distList.addAll(filteredDistributions);
366
367 return DescriptionUtility.orderDistributions(definedTermDao, omitLevels, distList, hiddenAreaMarkerTypes, null);
368 }
369
370
371 @Override
372 public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
373 long numberOfResults = dao.countTaxonNameDescriptions(name);
374
375 List<TaxonNameDescription> results = new ArrayList<>();
376 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
377 results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
378 }
379
380 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
381 }
382
383
384 @Override
385 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) {
386 long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
387
388 @SuppressWarnings("rawtypes")
389 List<DescriptionBase> results = new ArrayList<>();
390 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
391 results = dao.listDescriptions(type, hasImages, hasText, feature, pageSize, pageNumber,orderHints,propertyPaths);
392 }
393
394 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
395 }
396
397 /**
398 * FIXME Candidate for harmonization
399 * Rename: searchByDistribution
400 */
401 @Override
402 public Pager<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm presence, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
403 long numberOfResults = dao.countDescriptionByDistribution(namedAreas, presence);
404
405 List<TaxonDescription> results = new ArrayList<>();
406 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
407 results = dao.searchDescriptionByDistribution(namedAreas, presence, pageSize, pageNumber,orderHints,propertyPaths);
408 }
409
410 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
411 }
412
413 /**
414 * FIXME Candidate for harmonization
415 * move: descriptionElementService.search
416 */
417 @Override
418 // public Pager<T> searchElements(Class<? extends T> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
419 public <S extends DescriptionElementBase> Pager<S> searchElements(Class<S> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
420 long numberOfResults = descriptionElementDao.count(clazz, queryString);
421
422 List<S> results = new ArrayList<>();
423 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
424 results = (List<S>)descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
425 }
426
427 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
428 }
429
430 /**
431 * FIXME Candidate for harmonization
432 * descriptionElementService.find
433 */
434 @Override
435 public DescriptionElementBase getDescriptionElementByUuid(UUID uuid) {
436 return descriptionElementDao.findByUuid(uuid);
437 }
438
439 /**
440 * FIXME Candidate for harmonization
441 * descriptionElementService.load
442 */
443 @Override
444 public DescriptionElementBase loadDescriptionElement(UUID uuid, List<String> propertyPaths) {
445 return descriptionElementDao.load(uuid, propertyPaths);
446 }
447
448 /**
449 * FIXME Candidate for harmonization
450 * descriptionElementService.save
451 */
452 @Override
453 @Transactional(readOnly = false)
454 public UUID saveDescriptionElement(DescriptionElementBase descriptionElement) {
455 return descriptionElementDao.save(descriptionElement).getUuid();
456 }
457
458 /**
459 * FIXME Candidate for harmonization
460 * descriptionElementService.save
461 */
462 @Override
463 @Transactional(readOnly = false)
464 public Map<UUID, DescriptionElementBase> saveDescriptionElement(Collection<DescriptionElementBase> descriptionElements) {
465 return descriptionElementDao.saveAll(descriptionElements);
466 }
467
468 @Override
469 @Transactional(readOnly = false)
470 public List<MergeResult<DescriptionBase>> mergeDescriptionElements(Collection<TaxonDistributionDTO> descriptionElements, boolean returnTransientEntity) {
471 List<MergeResult<DescriptionBase>> mergedObjects = new ArrayList();
472 List<Distribution> toDelete = new ArrayList<>();
473 for(TaxonDistributionDTO obj : descriptionElements) {
474 Iterator<TaxonDescription> iterator = obj.getDescriptionsWrapper().getDescriptions().iterator();
475 while (iterator.hasNext()){
476 TaxonDescription desc = iterator.next();
477 mergedObjects.add(dao.merge(desc, returnTransientEntity));
478 }
479
480
481 }
482
483 return mergedObjects;
484 }
485
486 /**
487 * FIXME Candidate for harmonization
488 * descriptionElementService.delete
489 */
490 @Override
491 public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
492 return descriptionElementDao.delete(descriptionElement);
493 }
494
495
496 /* (non-Javadoc)
497 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescriptionElement(java.util.UUID)
498 */
499 @Override
500 public UUID deleteDescriptionElement(UUID descriptionElementUuid) {
501 return deleteDescriptionElement(descriptionElementDao.load(descriptionElementUuid));
502 }
503
504 @Override
505 @Transactional(readOnly = false)
506 public DeleteResult deleteDescription(DescriptionBase description) {
507 DeleteResult deleteResult = new DeleteResult();
508 description = load(description.getId(), Arrays.asList("descriptiveDataSets"));//avoid lazy init exception
509
510 if (description instanceof TaxonDescription){
511 TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
512 Taxon tax = taxDescription.getTaxon();
513 tax.removeDescription(taxDescription, true);
514 deleteResult.addUpdatedObject(tax);
515 }
516 else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
517 SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(description, SpecimenDescription.class);
518 SpecimenOrObservationBase specimen = specimenDescription.getDescribedSpecimenOrObservation();
519 specimen.removeDescription(specimenDescription);
520 deleteResult.addUpdatedObject(specimen);
521 }
522
523 Set<DescriptiveDataSet> descriptiveDataSets = description.getDescriptiveDataSets();
524 for (Iterator<DescriptiveDataSet> iterator = descriptiveDataSets.iterator(); iterator.hasNext();) {
525 iterator.next().removeDescription(description);
526 }
527
528 dao.delete(description);
529 deleteResult.addDeletedObject(description);
530 deleteResult.setCdmEntity(description);
531
532
533 return deleteResult;
534 }
535
536
537 /* (non-Javadoc)
538 * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescription(java.util.UUID)
539 */
540 @Override
541 @Transactional(readOnly = false)
542 public DeleteResult deleteDescription(UUID descriptionUuid) {
543 return deleteDescription(dao.load(descriptionUuid));
544 }
545
546
547 @Override
548 public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
549 return vocabularyDao.findByUuid(uuid);
550 }
551
552 @Override
553 @Deprecated
554 public <T extends DescriptionElementBase> List<T> getDescriptionElementsForTaxon(
555 Taxon taxon, Set<Feature> features,
556 Class<T> type, Integer pageSize,
557 Integer pageNumber, List<String> propertyPaths) {
558 return listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
559 }
560
561 @Override
562 public <T extends DescriptionElementBase> List<T> listDescriptionElementsForTaxon(
563 Taxon taxon, Set<Feature> features,
564 Class<T> type, Integer pageSize,
565 Integer pageNumber, List<String> propertyPaths) {
566 return dao.getDescriptionElementForTaxon(taxon.getUuid(), features, type, pageSize, pageNumber, propertyPaths);
567 }
568
569 @Override
570 public <T extends DescriptionElementBase> Pager<T> pageDescriptionElementsForTaxon(
571 Taxon taxon, Set<Feature> features,
572 Class<T> type, Integer pageSize,
573 Integer pageNumber, List<String> propertyPaths) {
574 if (logger.isDebugEnabled()){logger.debug(" get count ...");}
575 Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type);
576 List<T> descriptionElements;
577 if(AbstractPagerImpl.hasResultsInRange(count, pageNumber, pageSize)){ // no point checking again
578 if (logger.isDebugEnabled()){logger.debug(" get list ...");}
579 descriptionElements = listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
580 } else {
581 descriptionElements = new ArrayList<T>(0);
582 }
583 if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
584 return new DefaultPagerImpl<T>(pageNumber, count, pageSize, descriptionElements);
585 }
586
587
588 /* (non-Javadoc)
589 * @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)
590 */
591 @Override
592 public String generateNaturalLanguageDescription(FeatureTree featureTree,
593 TaxonDescription description, List<Language> preferredLanguages, String separator) {
594
595 Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
596
597 description = (TaxonDescription)load(description.getUuid());
598 featureTree = featureTreeDao.load(featureTree.getUuid());
599
600 StringBuilder naturalLanguageDescription = new StringBuilder();
601
602 MarkerType useMarkerType = (MarkerType) definedTermDao.load(UUID.fromString("2e6e42d9-e92a-41f4-899b-03c0ac64f039"));
603 boolean isUseDescription = false;
604 if(!description.getMarkers().isEmpty()) {
605 for (Marker marker: description.getMarkers()) {
606 MarkerType markerType = marker.getMarkerType();
607 if (markerType.equals(useMarkerType)) {
608 isUseDescription = true;
609 }
610
611 }
612 }
613
614 if(description.hasStructuredData() && !isUseDescription){
615
616
617 String lastCategory = null;
618 String categorySeparator = ". ";
619
620 List<TextData> textDataList;
621 TextData naturalLanguageDescriptionText = null;
622
623 boolean useMicroFormatQuantitativeDescriptionBuilder = false;
624
625 if(useMicroFormatQuantitativeDescriptionBuilder){
626
627 MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
628 naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
629 naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
630
631 } else {
632
633 naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
634 featureTree,
635 (description),
636 lang);
637 }
638
639 return naturalLanguageDescriptionText.getText(lang);
640
641 //
642 // boolean doItBetter = false;
643 //
644 // for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
645 // if(textData.getMultilanguageText().size() > 0){
646 //
647 // if (!textData.getFeature().equals(Feature.UNKNOWN())) {
648 // String featureLabel = textData.getFeature().getLabel(lang);
649 //
650 // if(doItBetter){
651 // /*
652 // * WARNING
653 // * The code lines below are desinged to handle
654 // * a special case where as the feature label contains
655 // * hierarchical information on the features. This code
656 // * exist only as a base for discussion, and is not
657 // * intendet to be used in production.
658 // */
659 // featureLabel = StringUtils.remove(featureLabel, '>');
660 //
661 // String[] labelTokens = StringUtils.split(featureLabel, '<');
662 // if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
663 // if(naturalLanguageDescription.length() > 0){
664 // naturalLanguageDescription.append(separator);
665 // }
666 // naturalLanguageDescription.append(labelTokens[1]);
667 // } else {
668 // if(naturalLanguageDescription.length() > 0){
669 // naturalLanguageDescription.append(categorySeparator);
670 // }
671 // naturalLanguageDescription.append(StringUtils.join(labelTokens));
672 // }
673 // lastCategory = labelTokens[0];
674 // // end of demo code
675 // } else {
676 // if(naturalLanguageDescription.length() > 0){
677 // naturalLanguageDescription.append(separator);
678 // }
679 // naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
680 // }
681 // } else {
682 // if(naturalLanguageDescription.length() > 0){
683 // naturalLanguageDescription.append(separator);
684 // }
685 // }
686 // String text = textData.getMultilanguageText().values().iterator().next().getText();
687 // naturalLanguageDescription.append(text);
688 //
689 // }
690 // }
691
692 }
693 else if (isUseDescription) {
694 //AT: Left Blank in case we need to generate a Natural language text string.
695 }
696 return naturalLanguageDescription.toString();
697 }
698
699
700 @Override
701 public boolean hasStructuredData(DescriptionBase<?> description) {
702 return load(description.getUuid()).hasStructuredData();
703 }
704
705
706 @Override
707 @Transactional(readOnly = false)
708 public UpdateResult moveDescriptionElementsToDescription(
709 Collection<DescriptionElementBase> descriptionElements,
710 DescriptionBase targetDescription,
711 boolean isCopy) {
712
713 UpdateResult result = new UpdateResult();
714 if (descriptionElements.isEmpty() ){
715 return result;
716 }
717
718 if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
719 //if the descriptionElements collection is the elements set of a description, put it in a separate set before to avoid concurrent modification exceptions
720 descriptionElements = new HashSet<DescriptionElementBase>(descriptionElements);
721 // descriptionElementsTmp.addAll(descriptionElements);
722 // descriptionElements = descriptionElementsTmp;
723 }
724 for (DescriptionElementBase element : descriptionElements){
725 DescriptionBase<?> description = element.getInDescription();
726 try {
727 DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
728 targetDescription.addElement(newElement);
729 } catch (CloneNotSupportedException e) {
730 throw new RuntimeException ("Clone not yet implemented for class " + element.getClass().getName(), e);
731 }
732 if (! isCopy){
733 description.removeElement(element);
734 if (description.getElements().isEmpty()){
735 if (description instanceof TaxonDescription){
736 TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
737 if (taxDescription.getTaxon() != null){
738 taxDescription.getTaxon().removeDescription((TaxonDescription)description);
739 }
740 }
741 dao.delete(description);
742
743 }else{
744 dao.saveOrUpdate(description);
745 result.addUpdatedObject(description);
746 }
747 }
748
749
750 }
751 dao.saveOrUpdate(targetDescription);
752 result.addUpdatedObject(targetDescription);
753 if (targetDescription instanceof TaxonDescription){
754 result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
755 }
756 return result;
757 }
758
759 @Override
760 @Transactional(readOnly = false)
761 public UpdateResult moveDescriptionElementsToDescription(
762 Set<UUID> descriptionElementUUIDs,
763 UUID targetDescriptionUuid,
764 boolean isCopy) {
765 Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
766 for(UUID deUuid : descriptionElementUUIDs) {
767 descriptionElements.add(descriptionElementDao.load(deUuid));
768 }
769 DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
770
771 return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
772 }
773
774 @Override
775 @Transactional(readOnly = false)
776 public UpdateResult moveDescriptionElementsToDescription(
777 Set<UUID> descriptionElementUUIDs,
778 UUID targetTaxonUuid,
779 String moveMessage,
780 boolean isCopy) {
781 Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
782 DescriptionBase targetDescription = TaxonDescription.NewInstance(targetTaxon);
783 targetDescription.setTitleCache(moveMessage, true);
784 Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
785 annotation.setAnnotationType(AnnotationType.TECHNICAL());
786 targetDescription.addAnnotation(annotation);
787
788 targetDescription = dao.save(targetDescription);
789 Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
790 for(UUID deUuid : descriptionElementUUIDs) {
791 descriptionElements.add(descriptionElementDao.load(deUuid));
792 }
793
794 return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
795 }
796
797 @Override
798 public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
799 Integer pageNumber){
800 List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
801 int startIndex= pageNumber * pageSize;
802 int toIndex = Math.min(startIndex + pageSize, results.size());
803 List<TermDto> page = results.subList(startIndex, toIndex);
804 return new DefaultPagerImpl<TermDto>(pageNumber, results.size(), pageSize, page);
805 }
806
807
808 @Override
809 @Transactional(readOnly = false)
810 public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon) {
811 List<TaxonDescription> descriptions = new ArrayList(sourceTaxon.getDescriptions());
812 UpdateResult result = new UpdateResult();
813 result.addUpdatedObject(sourceTaxon);
814 result.addUpdatedObject(targetTaxon);
815 for(TaxonDescription description : descriptions){
816
817 String moveMessage = String.format("Description moved from %s", sourceTaxon);
818 if(description.isProtectedTitleCache()){
819 String separator = "";
820 if(!StringUtils.isBlank(description.getTitleCache())){
821 separator = " - ";
822 }
823 description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
824 }
825 Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
826 annotation.setAnnotationType(AnnotationType.TECHNICAL());
827 description.addAnnotation(annotation);
828 targetTaxon.addDescription(description);
829 }
830 return result;
831 }
832
833 @Override
834 @Transactional(readOnly = false)
835 public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid) {
836 Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
837 Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
838 return moveTaxonDescriptions(sourceTaxon, targetTaxon);
839
840 }
841
842 @Override
843 @Transactional(readOnly = false)
844 public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid){
845 UpdateResult result = new UpdateResult();
846 TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
847
848 Taxon sourceTaxon = description.getTaxon();
849 String moveMessage = String.format("Description moved from %s", sourceTaxon);
850 if(description.isProtectedTitleCache()){
851 String separator = "";
852 if(!StringUtils.isBlank(description.getTitleCache())){
853 separator = " - ";
854 }
855 description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
856 }
857 Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
858 annotation.setAnnotationType(AnnotationType.TECHNICAL());
859 description.addAnnotation(annotation);
860 Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
861 targetTaxon.addDescription(description);
862 result.addUpdatedObject(targetTaxon);
863 result.addUpdatedObject(sourceTaxon);
864 // dao.merge(description);
865 return result;
866
867 }
868
869
870 }