96259d88d9f31e9b6478e64f3d09e69c01101f99
[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 package eu.etaxonomy.cdm.api.service;
10
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Set;
19 import java.util.UUID;
20 import java.util.stream.Collectors;
21
22 import org.apache.commons.lang3.StringUtils;
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.hibernate.query.Query;
26 import org.springframework.beans.factory.annotation.Autowired;
27 import org.springframework.stereotype.Service;
28 import org.springframework.transaction.annotation.Transactional;
29
30 import eu.etaxonomy.cdm.api.service.description.MissingMaximumMode;
31 import eu.etaxonomy.cdm.api.service.description.MissingMinimumMode;
32 import eu.etaxonomy.cdm.api.service.description.StructuredDescriptionAggregation;
33 import eu.etaxonomy.cdm.api.service.dto.TaxonDistributionDTO;
34 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
35 import eu.etaxonomy.cdm.api.service.pager.Pager;
36 import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
37 import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
38 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
39 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
40 import eu.etaxonomy.cdm.format.description.MicroFormatQuantitativeDescriptionBuilder;
41 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
42 import eu.etaxonomy.cdm.model.common.Annotation;
43 import eu.etaxonomy.cdm.model.common.AnnotationType;
44 import eu.etaxonomy.cdm.model.common.CdmBase;
45 import eu.etaxonomy.cdm.model.common.Language;
46 import eu.etaxonomy.cdm.model.common.Marker;
47 import eu.etaxonomy.cdm.model.common.MarkerType;
48 import eu.etaxonomy.cdm.model.description.CategoricalData;
49 import eu.etaxonomy.cdm.model.description.DescriptionBase;
50 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
51 import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
52 import eu.etaxonomy.cdm.model.description.DescriptionType;
53 import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
54 import eu.etaxonomy.cdm.model.description.Feature;
55 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
56 import eu.etaxonomy.cdm.model.description.MeasurementUnit;
57 import eu.etaxonomy.cdm.model.description.QuantitativeData;
58 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
59 import eu.etaxonomy.cdm.model.description.StateData;
60 import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
61 import eu.etaxonomy.cdm.model.description.StatisticalMeasurementValue;
62 import eu.etaxonomy.cdm.model.description.TaxonDescription;
63 import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
64 import eu.etaxonomy.cdm.model.description.TextData;
65 import eu.etaxonomy.cdm.model.location.NamedArea;
66 import eu.etaxonomy.cdm.model.media.Media;
67 import eu.etaxonomy.cdm.model.name.TaxonName;
68 import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
69 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
70 import eu.etaxonomy.cdm.model.reference.CdmLinkSource;
71 import eu.etaxonomy.cdm.model.reference.ICdmTarget;
72 import eu.etaxonomy.cdm.model.taxon.Taxon;
73 import eu.etaxonomy.cdm.model.term.DefinedTerm;
74 import eu.etaxonomy.cdm.model.term.DefinedTermBase;
75 import eu.etaxonomy.cdm.model.term.TermTree;
76 import eu.etaxonomy.cdm.model.term.TermVocabulary;
77 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
78 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionElementDao;
79 import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
80 import eu.etaxonomy.cdm.persistence.dao.description.IStatisticalMeasurementValueDao;
81 import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
82 import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
83 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
84 import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
85 import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
86 import eu.etaxonomy.cdm.persistence.dao.term.ITermNodeDao;
87 import eu.etaxonomy.cdm.persistence.dao.term.ITermTreeDao;
88 import eu.etaxonomy.cdm.persistence.dao.term.ITermVocabularyDao;
89 import eu.etaxonomy.cdm.persistence.dto.CategoricalDataDto;
90 import eu.etaxonomy.cdm.persistence.dto.DescriptionBaseDto;
91 import eu.etaxonomy.cdm.persistence.dto.DescriptionElementDto;
92 import eu.etaxonomy.cdm.persistence.dto.MergeResult;
93 import eu.etaxonomy.cdm.persistence.dto.QuantitativeDataDto;
94 import eu.etaxonomy.cdm.persistence.dto.SortableTaxonNodeQueryResult;
95 import eu.etaxonomy.cdm.persistence.dto.StateDataDto;
96 import eu.etaxonomy.cdm.persistence.dto.StatisticalMeasurementValueDto;
97 import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
98 import eu.etaxonomy.cdm.persistence.dto.TermDto;
99 import eu.etaxonomy.cdm.persistence.query.OrderHint;
100 import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
101
102 /**
103 * @author a.mueller
104 * @author a.kohlbecker
105 *
106 * @since 24.06.2008
107 */
108 @Service
109 @Transactional(readOnly = true)
110 public class DescriptionServiceImpl
111 extends IdentifiableServiceBase<DescriptionBase,IDescriptionDao>
112 implements IDescriptionService {
113
114 private static final Logger logger = LogManager.getLogger();
115
116 protected IDescriptionElementDao descriptionElementDao;
117 protected ITermTreeDao featureTreeDao;
118 protected IDescriptiveDataSetDao descriptiveDataSetDao;
119 protected ITermNodeDao termNodeDao;
120 protected ITermVocabularyDao vocabularyDao;
121 protected IDefinedTermDao definedTermDao;
122 protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
123 protected ITaxonDao taxonDao;
124 protected ITaxonNameDao nameDao;
125 protected IOccurrenceDao occurrenceDao;
126 protected ITaxonNodeDao taxonNodeDao;
127 protected IDescriptiveDataSetDao dataSetDao;
128 protected ITermService termService;
129
130 //TODO change to Interface
131 private NaturalLanguageGenerator naturalLanguageGenerator;
132
133 @Autowired
134 protected void setFeatureTreeDao(ITermTreeDao featureTreeDao) {
135 this.featureTreeDao = featureTreeDao;
136 }
137
138 @Autowired
139 protected void setDescriptiveDataSetDao(IDescriptiveDataSetDao descriptiveDataSetDao) {
140 this.descriptiveDataSetDao = descriptiveDataSetDao;
141 }
142
143 @Autowired
144 protected void setTermNodeDao(ITermNodeDao featureNodeDao) {
145 this.termNodeDao = featureNodeDao;
146 }
147
148 @Autowired
149 protected void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
150 this.vocabularyDao = vocabularyDao;
151 }
152
153 @Autowired
154 protected void setDefinedTermDao(IDefinedTermDao definedTermDao) {
155 this.definedTermDao = definedTermDao;
156 }
157
158 @Autowired
159 protected void setTermService(ITermService definedTermService) {
160 this.termService = definedTermService;
161 }
162
163
164 @Autowired
165 protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao) {
166 this.statisticalMeasurementValueDao = statisticalMeasurementValueDao;
167 }
168
169 @Autowired
170 protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao) {
171 this.descriptionElementDao = descriptionElementDao;
172 }
173
174 @Autowired
175 protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator) {
176 this.naturalLanguageGenerator = naturalLanguageGenerator;
177 }
178
179 @Autowired
180 protected void setTaxonDao(ITaxonDao taxonDao) {
181 this.taxonDao = taxonDao;
182 }
183
184 @Autowired
185 protected void setTaxonNodeDao(ITaxonNodeDao taxonNodeDao) {
186 this.taxonNodeDao = taxonNodeDao;
187 }
188
189 @Autowired
190 protected void setDataSetDao(IDescriptiveDataSetDao dataSetDao) {
191 this.dataSetDao = dataSetDao;
192 }
193
194 public DescriptionServiceImpl() {
195 logger.debug("Load DescriptionService Bean");
196 }
197
198 @Override
199 @Transactional(readOnly = false)
200 public UpdateResult updateCaches(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
201 if (clazz == null){
202 clazz = DescriptionBase.class;
203 }
204 return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
205 }
206
207 @Override
208 public TermVocabulary<Feature> getDefaultFeatureVocabulary(){
209 String uuidFeature = "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
210 UUID featureUuid = UUID.fromString(uuidFeature);
211 return vocabularyDao.findByUuid(featureUuid);
212 }
213
214 @Override
215 @Autowired
216 protected void setDao(IDescriptionDao dao) {
217 this.dao = dao;
218 }
219
220 @Override
221 public long count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
222 return dao.countDescriptions(type, hasImages, hasText, feature);
223 }
224
225 @Override
226 public <T extends DescriptionElementBase> Pager<T> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
227 Set<Feature> features, Class<T> type, boolean includeUnpublished,
228 Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
229
230 List<T> results = listDescriptionElements(description, descriptionType, features, type, includeUnpublished,
231 pageSize, pageNumber, propertyPaths);
232 return new DefaultPagerImpl<>(pageNumber, Integer.valueOf(results.size()).longValue(), pageSize, results);
233 }
234
235 @Override
236 public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
237 Class<? extends DescriptionBase> descriptionType,
238 Set<Feature> features, Class<T> type, boolean includeUnpublished,
239 Integer pageSize, Integer pageNumber,
240 List<String> propertyPaths) {
241
242 long numberOfResults = dao.countDescriptionElements(description, descriptionType, features, type, includeUnpublished);
243 List<T> results = new ArrayList<>();
244 if(AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)) {
245 results = dao.getDescriptionElements(description, descriptionType, features, type, includeUnpublished, pageSize, pageNumber, propertyPaths);
246 }
247 return results;
248 }
249
250 @Override
251 public Pager<Media> getMedia(DescriptionElementBase descriptionElement, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
252 Long numberOfResults = descriptionElementDao.countMedia(descriptionElement);
253
254 List<Media> results = new ArrayList<>();
255 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
256 results = descriptionElementDao.getMedia(descriptionElement, pageSize, pageNumber, propertyPaths);
257 }
258
259 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
260 }
261
262 @Override
263 public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
264 Set<MarkerType> markerTypes = null;
265 Set<DescriptionType> descriptionTypes = null;
266 return pageTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
267 }
268
269 @Override
270 public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
271 Set<MarkerType> markerTypes = null;
272 Set<DescriptionType> descriptionTypes = null;
273 return listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
274 }
275
276 @Override
277 public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Set<MarkerType> markerTypes, Set<DescriptionType> descriptionTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
278 long numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes);
279
280 List<TaxonDescription> results = new ArrayList<>();
281 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
282 results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
283 }
284
285 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
286 }
287
288 @Override
289 public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Set<MarkerType> markerTypes, Set<DescriptionType> descriptionTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
290 List<TaxonDescription> results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
291 return results;
292 }
293
294
295 @Override
296 public List<Media> listTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths){
297 return this.dao.listTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes, pageSize, pageNumber, propertyPaths);
298 }
299
300 @Override
301 public int countTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes){
302 return this.dao.countTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes);
303 }
304
305 @Override
306 public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
307 long numberOfResults = dao.countTaxonNameDescriptions(name);
308
309 List<TaxonNameDescription> results = new ArrayList<>();
310 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
311 results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
312 }
313
314 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
315 }
316
317
318 @Override
319 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) {
320 long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
321
322 @SuppressWarnings("rawtypes")
323 List<DescriptionBase> results = new ArrayList<>();
324 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
325 results = dao.listDescriptions(type, hasImages, hasText, feature, pageSize, pageNumber,orderHints,propertyPaths);
326 }
327
328 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
329 }
330
331 /**
332 * FIXME Candidate for harmonization
333 * move: descriptionElementService.search
334 */
335 @Override
336 // public Pager<T> searchElements(Class<? extends T> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
337 public <S extends DescriptionElementBase> Pager<S> searchElements(Class<S> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
338 long numberOfResults = descriptionElementDao.count(clazz, queryString);
339
340 List<S> results = new ArrayList<>();
341 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
342 results = (List<S>)descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
343 }
344
345 return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
346 }
347
348 @Override
349 @Transactional(readOnly = false)
350 public List<MergeResult<DescriptionBase>> mergeDescriptionElements(Collection<TaxonDistributionDTO> descriptionElements, boolean returnTransientEntity) {
351 List<MergeResult<DescriptionBase>> mergedObjects = new ArrayList<>();
352
353 for(TaxonDistributionDTO obj : descriptionElements) {
354 Iterator<TaxonDescription> iterator = obj.getDescriptionsWrapper().getDescriptions().iterator();
355 List<DescriptionBase> list = new ArrayList(obj.getDescriptionsWrapper().getDescriptions());
356 // Map<UUID, DescriptionBase> map = dao.saveOrUpdateAll(list);
357 // MergeResult<DescriptionBase> mergeResult = new MergeResult<DescriptionBase>(mergedEntity, newEntities)
358 // mergedObjects.add(map.values());
359 while (iterator.hasNext()){
360 TaxonDescription desc = iterator.next();
361 mergedObjects.add(dao.merge(desc, returnTransientEntity));
362 }
363 }
364
365 return mergedObjects;
366 }
367
368 @Override
369 @Transactional(readOnly = false)
370 public UpdateResult mergeDescriptions(Collection<DescriptionBaseDto> descriptions, UUID descriptiveDataSetUuid) {
371
372 UpdateResult result = new UpdateResult();
373 DescriptiveDataSet dataSet = descriptiveDataSetDao.load(descriptiveDataSetUuid);
374 Set<DescriptionBase> descriptionsOfDataSet = dataSet.getDescriptions();
375 HashMap<UUID, Set<DescriptionBase>> descriptionSpecimenMap = new HashMap<>();
376 Set<DescriptionBase> specimenDescriptions;
377 for (DescriptionBase<?> descriptionBase: descriptionsOfDataSet){
378 if (descriptionBase.getDescribedSpecimenOrObservation() != null){
379 specimenDescriptions = descriptionSpecimenMap.get(descriptionBase.getDescribedSpecimenOrObservation().getUuid());
380 if (specimenDescriptions == null){
381 specimenDescriptions = new HashSet<>();
382 }
383 specimenDescriptions.add(descriptionBase);
384 descriptionSpecimenMap.put(descriptionBase.getDescribedSpecimenOrObservation().getUuid(), specimenDescriptions);
385 }
386 if (descriptionBase instanceof TaxonDescription){
387 specimenDescriptions = descriptionSpecimenMap.get(((TaxonDescription)descriptionBase).getTaxon().getUuid());
388 if (specimenDescriptions == null){
389 specimenDescriptions = new HashSet<>();
390 }
391 specimenDescriptions.add(descriptionBase);
392 descriptionSpecimenMap.put(((TaxonDescription)descriptionBase).getTaxon().getUuid(), specimenDescriptions);
393 }
394 if (descriptionBase instanceof TaxonNameDescription){
395 specimenDescriptions = descriptionSpecimenMap.get(((TaxonNameDescription)descriptionBase).getTaxonName().getUuid());
396 if (specimenDescriptions == null){
397 specimenDescriptions = new HashSet<>();
398 }
399 specimenDescriptions.add(descriptionBase);
400 descriptionSpecimenMap.put(((TaxonNameDescription)descriptionBase).getTaxonName().getUuid(), specimenDescriptions);
401 }
402 }
403 MergeResult<DescriptionBase> mergeResult = null;
404 for(DescriptionBaseDto descDto : descriptions) {
405
406 UUID descriptionUUID = descDto.getDescriptionUuid();
407 DescriptionBase<?> description = load(descriptionUUID);
408
409 UUID describedObjectUuid = null;
410 if (description instanceof SpecimenDescription){
411 describedObjectUuid = descDto.getSpecimenDto().getUuid();
412 }else if (description instanceof TaxonDescription){
413 describedObjectUuid = descDto.getTaxonDto().getUuid();
414 }else if (description instanceof TaxonNameDescription){
415 describedObjectUuid = descDto.getNameDto().getUuid();
416 }
417
418 Set<DescriptionBase> descSpecimen = descriptionSpecimenMap.get(describedObjectUuid);
419
420 if (descSpecimen != null ){
421
422 // TODO: elements are Dtos now, no cdm entities, needs to get the value and replace or create new description element
423 Set<DescriptionElementDto> elements = new HashSet<>();
424 for (Object element: descDto.getElements()){
425 elements.add((DescriptionElementDto)element);
426 }
427
428 DescriptionBase<?> desc = null;
429 for (DescriptionBase<?> tempDesc: descSpecimen){
430 if (tempDesc.getUuid().equals(descDto.getDescriptionUuid())){
431 desc = tempDesc;
432 break;
433 }
434 }
435
436 Set<DescriptionElementBase> removeElements = new HashSet<>();
437 Set<DescriptionElementBase> descriptionElements = desc.getElements();
438 for (DescriptionElementBase elementBase: descriptionElements){
439 UUID descElementUuid = elementBase.getUuid();
440 if (descElementUuid != null){
441 List<DescriptionElementDto> equalUuidsElements = elements.stream().filter( e -> e != null && e.getElementUuid() != null && e.getElementUuid().equals(descElementUuid)).collect(Collectors.toList());
442 if (equalUuidsElements.size() == 0 || (equalUuidsElements.size() == 1 && equalUuidsElements.get(0)instanceof QuantitativeDataDto && (((QuantitativeDataDto)equalUuidsElements.get(0)).getValues().isEmpty()) &&(((QuantitativeDataDto)equalUuidsElements.get(0)).getNoDataStatus() == null))){
443 removeElements.add(elementBase);
444 }
445 }
446 }
447 if (!removeElements.isEmpty()){
448 for (DescriptionElementBase el: removeElements){
449 desc.removeElement(el);
450 }
451 }
452
453 // description.setDescribedSpecimenOrObservation(null);
454
455 for (DescriptionElementDto descElement: elements){
456 if (descElement == null){
457 continue;
458 }
459 UUID descElementUuid = descElement.getElementUuid();
460 // if (descElement instanceof CategoricalDataDto && ((CategoricalDataDto)descElement).getStates().isEmpty() || descElement instanceof QuantitativeDataDto && ((QuantitativeDataDto)descElement).getValues().isEmpty()){
461 // continue;
462 // }
463 List<DescriptionElementBase> equalUuidsElements = descriptionElements.stream().filter( e -> e.getUuid().equals(descElementUuid)).collect(Collectors.toList());
464 Feature feature = DefinedTermBase.getTermByUUID(descElement.getFeatureUuid(), Feature.class);
465
466 if (equalUuidsElements.size() == 0){
467 if (descElement instanceof CategoricalDataDto){
468
469 CategoricalData elementBase = CategoricalData.NewInstance(feature);
470 List<StateDataDto> stateDtos = ((CategoricalDataDto)descElement).getStates();
471 for (StateDataDto dataDto: stateDtos){
472 //create new statedata
473 if (dataDto == null || dataDto.getState() == null){
474 continue;
475 }
476 DefinedTermBase<?> newState = DefinedTermBase.getTermByUUID(dataDto.getState().getUuid(), DefinedTermBase.class);
477 StateData newStateData = StateData.NewInstance(newState);
478 //add modifier
479 if (dataDto.getModifiers()!= null && !dataDto.getModifiers().isEmpty()) {
480 DefinedTerm modifier = DefinedTermBase.getTermByUUID(dataDto.getModifiers().iterator().next().getUuid(), DefinedTerm.class);
481 newStateData.addModifier(modifier);
482 }
483
484 elementBase.addStateData(newStateData);
485 }
486 desc.addElement(elementBase);
487 elementBase.setNoDataStatus(((CategoricalDataDto)descElement).getNoDataStatus());
488 }
489 if (descElement instanceof QuantitativeDataDto){
490
491 QuantitativeData data = QuantitativeData.NewInstance(feature);
492 if (((QuantitativeDataDto) descElement).getMeasurementUnit() != null){
493 MeasurementUnit unit = DefinedTermBase.getTermByClassAndUUID(MeasurementUnit.class, ((QuantitativeDataDto) descElement).getMeasurementUnit().getUuid());
494 data.setUnit(unit);
495 }
496 Set<StatisticalMeasurementValue> statisticalValues = new HashSet<>();
497 Set<StatisticalMeasurementValueDto> valueDtos = ((QuantitativeDataDto)descElement).getValues();
498 data.getStatisticalValues().clear();
499 for (StatisticalMeasurementValueDto dataDto: valueDtos){
500 //create new statedata
501 StatisticalMeasure sm = DefinedTermBase.getTermByClassAndUUID(StatisticalMeasure.class, dataDto.getType().getUuid());
502 StatisticalMeasurementValue newStatisticalMeasurement = StatisticalMeasurementValue.NewInstance(sm, dataDto.getValue());
503 statisticalValues.add(newStatisticalMeasurement);
504 data.addStatisticalValue(newStatisticalMeasurement);
505 }
506
507 // data.getStatisticalValues().addAll(statisticalValues);
508 data = StructuredDescriptionAggregation.handleMissingMinOrMax(data,
509 MissingMinimumMode.MinToZero, MissingMaximumMode.MaxToMin);
510 desc.addElement(data);
511 data.setNoDataStatus(((QuantitativeDataDto)descElement).getNoDataStatus());
512 }
513
514 //create new element
515 }else{
516 DescriptionElementBase elementBase = equalUuidsElements.get(0);
517 if (elementBase.isInstanceOf(CategoricalData.class)){
518 CategoricalData data = HibernateProxyHelper.deproxy(elementBase, CategoricalData.class);
519 List<StateData> states = new ArrayList<>(data.getStateData());
520 List<StateDataDto> stateDtos = ((CategoricalDataDto)descElement).getStates();
521
522 data.getStateData().clear();
523 if (stateDtos.isEmpty() && ((CategoricalDataDto)descElement).getNoDataStatus() == null){
524 desc.removeElement(data);
525 }else{
526 for (StateDataDto dataDto: stateDtos){
527 if (dataDto == null) {
528 continue;
529 }
530 DefinedTermBase<?> newState = DefinedTermBase.getTermByUUID(dataDto.getState().getUuid(), DefinedTermBase.class);
531 StateData newStateData = StateData.NewInstance(newState);
532 data.addStateData(newStateData);
533 if (dataDto.getModifiers()!= null && !dataDto.getModifiers().isEmpty()) {
534 DefinedTerm modifier = DefinedTermBase.getTermByUUID(dataDto.getModifiers().iterator().next().getUuid(), DefinedTerm.class);
535 newStateData.addModifier(modifier);
536 }
537 }
538
539 data.setNoDataStatus(((CategoricalDataDto)descElement).getNoDataStatus());
540 }
541 }else if (elementBase.isInstanceOf(QuantitativeData.class)){
542 QuantitativeData data = HibernateProxyHelper.deproxy(elementBase, QuantitativeData.class);
543
544 Set<StatisticalMeasurementValue> statisticalValues = new HashSet<>();
545 if (((QuantitativeDataDto) descElement).getMeasurementUnit() != null){
546 MeasurementUnit unit = DefinedTermBase.getTermByClassAndUUID(MeasurementUnit.class, ((QuantitativeDataDto) descElement).getMeasurementUnit().getUuid());
547 if (data.getUnit() == null || (data.getUnit() != null && !data.getUnit().equals(unit))){
548 data.setUnit(unit);
549 }
550 }
551 Set<StatisticalMeasurementValueDto> valueDtos = ((QuantitativeDataDto)descElement).getValues();
552 data.getStatisticalValues().clear();
553 if (valueDtos.isEmpty() && ((QuantitativeDataDto)descElement).getNoDataStatus() == null){
554 desc.removeElement(data);
555 }else{
556 for (StatisticalMeasurementValueDto dataDto: valueDtos){
557 //create new statedata
558 StatisticalMeasure statMeasure = DefinedTermBase.getTermByClassAndUUID(StatisticalMeasure.class, dataDto.getType().getUuid());
559
560 StatisticalMeasurementValue newStatisticalMeasurement = StatisticalMeasurementValue.NewInstance(statMeasure, dataDto.getValue());
561 statisticalValues.add(newStatisticalMeasurement);
562 data.addStatisticalValue(newStatisticalMeasurement);
563 }
564
565 // data.getStatisticalValues().addAll(statisticalValues);
566 data = StructuredDescriptionAggregation.handleMissingMinOrMax(data,
567 MissingMinimumMode.MinToZero, MissingMaximumMode.MaxToMin);
568 data.setNoDataStatus(((QuantitativeDataDto)descElement).getNoDataStatus());
569 }
570
571 }
572 }
573 //remove deleted elements
574
575 }
576
577 descriptionSpecimenMap.get(describedObjectUuid).add(desc);
578
579 description = desc;
580 }
581 try{
582 if (description != null){
583 mergeResult = dao.merge(description, true);
584 result.addUpdatedObject( mergeResult.getMergedEntity());
585 }
586
587 // if (description instanceof SpecimenDescription){
588 // result.addUpdatedObject(mergeResult.getMergedEntity().getDescribedSpecimenOrObservation());
589 // }else if (description instanceof TaxonDescription){
590 // result.addUpdatedObject(((TaxonDescription)mergeResult.getMergedEntity()).getTaxon());
591 // }else if (description instanceof TaxonNameDescription){
592 // result.addUpdatedObject(((TaxonNameDescription)mergeResult.getMergedEntity()).getTaxonName());
593 // }
594 }catch(Exception e){
595 e.printStackTrace();
596 }
597
598 }
599
600 return result;
601 }
602
603 @Override
604 @Transactional(readOnly = false)
605 public DeleteResult deleteDescription(DescriptionBase<?> description) {
606
607 DeleteResult deleteResult = new DeleteResult();
608 if (description == null){
609 return deleteResult;
610 }
611 //avoid lazy init exception
612 description = load(description.getId(), Arrays.asList("descriptiveDataSets"));
613
614 deleteResult = isDeletable(description.getUuid());
615 if (deleteResult.getRelatedObjects() != null && deleteResult.getRelatedObjects().size() == 1){
616 Iterator<CdmBase> relObjects = deleteResult.getRelatedObjects().iterator();
617 CdmBase next = relObjects.next();
618 if (next instanceof CdmLinkSource){
619 CdmLinkSource source = (CdmLinkSource)next;
620 ICdmTarget target = source.getTarget();
621
622
623 }
624 }
625 if (deleteResult.isOk() ){
626 CdmBase.deproxy(description);
627 if (description instanceof TaxonDescription){
628 TaxonDescription taxDescription = (TaxonDescription)description;
629 Taxon tax = taxDescription.getTaxon();
630 if (tax != null){
631 tax.removeDescription(taxDescription, true);
632 deleteResult.addUpdatedObject(tax);
633 }
634 }
635 else if (description instanceof SpecimenDescription){
636 SpecimenDescription specimenDescription = (SpecimenDescription)description;
637 SpecimenOrObservationBase<?> specimen = specimenDescription.getDescribedSpecimenOrObservation();
638 if (specimen != null){
639 specimen.removeDescription(specimenDescription);
640 deleteResult.addUpdatedObject(specimen);
641 }
642 }
643
644 for (DescriptiveDataSet dataset : description.getDescriptiveDataSets()) {
645 dataset.removeDescription(description);
646 }
647
648 dao.delete(description);
649 deleteResult.addDeletedObject(description);
650 deleteResult.setCdmEntity(description);
651 }else{
652 logger.info(deleteResult.getExceptions().toString());
653 }
654
655 return deleteResult;
656 }
657
658 @Override
659 @Transactional(readOnly = false)
660 public DeleteResult deleteDescription(UUID descriptionUuid) {
661 return deleteDescription(dao.load(descriptionUuid));
662 }
663
664
665
666 @Override
667 public DeleteResult isDeletable(UUID descriptionUuid){
668 DeleteResult result = new DeleteResult();
669 DescriptionBase<?> description = this.load(descriptionUuid);
670 Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(description);
671
672 if (references == null || references.isEmpty()){
673 return result;
674 }
675 for (CdmBase ref: references){
676 if (description instanceof TaxonDescription && ref instanceof Taxon && ref.equals(((TaxonDescription)description).getTaxon())){
677 continue;
678 } else if (description instanceof TaxonNameDescription && ref instanceof TaxonName && ref.equals(((TaxonNameDescription)description).getTaxonName())){
679 continue;
680 } else if (description instanceof SpecimenDescription && ref instanceof SpecimenOrObservationBase && ref.equals(((SpecimenDescription)description).getDescribedSpecimenOrObservation())){
681 continue;
682 } else if (ref instanceof DescriptionElementBase){
683 continue;
684 } else if (ref instanceof CdmLinkSource && ((CdmLinkSource)ref).hasNoTarget()) {
685 continue; //maybe only workaround #9801
686 }else {
687 String message = "The description can't be completely deleted because it is referenced by " + ref.getUserFriendlyTypeName() ;
688 result.setAbort();
689 result.addException(new ReferencedObjectUndeletableException(message));
690 result.addRelatedObject(ref);
691 }
692 }
693
694 return result;
695 }
696
697 @Override
698 @Deprecated
699 public <T extends DescriptionElementBase> List<T> getDescriptionElementsForTaxon(
700 Taxon taxon, Set<Feature> features,
701 Class<T> type, boolean includeUnpublished,
702 Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
703
704 return listDescriptionElementsForTaxon(taxon, features, type, includeUnpublished,
705 pageSize, pageNumber, propertyPaths);
706 }
707
708 @Override
709 public <T extends DescriptionElementBase> List<T> listDescriptionElementsForTaxon(
710 Taxon taxon, Set<Feature> features,
711 Class<T> type, boolean includePublished,
712 Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
713
714 return dao.getDescriptionElementForTaxon(taxon.getUuid(), features, type, includePublished,
715 pageSize, pageNumber, propertyPaths);
716 }
717
718 @Override
719 public <T extends DescriptionElementBase> Pager<T> pageDescriptionElementsForTaxon(
720 Taxon taxon, Set<Feature> features,
721 Class<T> type, boolean includeUnpublished,
722 Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
723
724 if (logger.isDebugEnabled()){logger.debug(" get count ...");}
725 Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type, includeUnpublished);
726 List<T> descriptionElements;
727 if(AbstractPagerImpl.hasResultsInRange(count, pageNumber, pageSize)){ // no point checking again
728 if (logger.isDebugEnabled()){logger.debug(" get list ...");}
729 descriptionElements = listDescriptionElementsForTaxon(taxon, features, type, includeUnpublished,
730 pageSize, pageNumber, propertyPaths);
731 } else {
732 descriptionElements = new ArrayList<>(0);
733 }
734 if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
735 return new DefaultPagerImpl<>(pageNumber, count, pageSize, descriptionElements);
736 }
737
738 @Override
739 public String generateNaturalLanguageDescription(TermTree featureTree,
740 TaxonDescription description, List<Language> preferredLanguages, String separator) {
741
742 Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
743
744 description = (TaxonDescription)load(description.getUuid());
745 featureTree = featureTreeDao.load(featureTree.getUuid());
746
747 StringBuilder naturalLanguageDescription = new StringBuilder();
748
749 MarkerType useMarkerType = (MarkerType) definedTermDao.load(UUID.fromString("2e6e42d9-e92a-41f4-899b-03c0ac64f039"));
750 boolean isUseDescription = false;
751 if(!description.getMarkers().isEmpty()) {
752 for (Marker marker: description.getMarkers()) {
753 MarkerType markerType = marker.getMarkerType();
754 if (markerType.equals(useMarkerType)) {
755 isUseDescription = true;
756 }
757
758 }
759 }
760
761 if(description.hasStructuredData() && !isUseDescription){
762
763
764 String lastCategory = null;
765 String categorySeparator = ". ";
766
767 List<TextData> textDataList;
768 TextData naturalLanguageDescriptionText = null;
769
770 boolean useMicroFormatQuantitativeDescriptionBuilder = false;
771
772 if(useMicroFormatQuantitativeDescriptionBuilder){
773
774 MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
775 naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
776 naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
777
778 } else {
779
780 naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
781 featureTree,
782 (description),
783 lang);
784 }
785
786 return naturalLanguageDescriptionText.getText(lang);
787
788 //
789 // boolean doItBetter = false;
790 //
791 // for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
792 // if(textData.getMultilanguageText().size() > 0){
793 //
794 // if (!textData.getFeature().equals(Feature.UNKNOWN())) {
795 // String featureLabel = textData.getFeature().getLabel(lang);
796 //
797 // if(doItBetter){
798 // /*
799 // * WARNING
800 // * The code lines below are desinged to handle
801 // * a special case where as the feature label contains
802 // * hierarchical information on the features. This code
803 // * exist only as a base for discussion, and is not
804 // * intendet to be used in production.
805 // */
806 // featureLabel = StringUtils.remove(featureLabel, '>');
807 //
808 // String[] labelTokens = StringUtils.split(featureLabel, '<');
809 // if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
810 // if(naturalLanguageDescription.length() > 0){
811 // naturalLanguageDescription.append(separator);
812 // }
813 // naturalLanguageDescription.append(labelTokens[1]);
814 // } else {
815 // if(naturalLanguageDescription.length() > 0){
816 // naturalLanguageDescription.append(categorySeparator);
817 // }
818 // naturalLanguageDescription.append(StringUtils.join(labelTokens));
819 // }
820 // lastCategory = labelTokens[0];
821 // // end of demo code
822 // } else {
823 // if(naturalLanguageDescription.length() > 0){
824 // naturalLanguageDescription.append(separator);
825 // }
826 // naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
827 // }
828 // } else {
829 // if(naturalLanguageDescription.length() > 0){
830 // naturalLanguageDescription.append(separator);
831 // }
832 // }
833 // String text = textData.getMultilanguageText().values().iterator().next().getText();
834 // naturalLanguageDescription.append(text);
835 //
836 // }
837 // }
838
839 }
840 else if (isUseDescription) {
841 //AT: Left Blank in case we need to generate a Natural language text string.
842 }
843 return naturalLanguageDescription.toString();
844 }
845
846
847 @Override
848 public boolean hasStructuredData(DescriptionBase<?> description) {
849 return load(description.getUuid()).hasStructuredData();
850 }
851
852
853 @Override
854 // @Transactional(readOnly = false)
855 public UpdateResult moveDescriptionElementsToDescription(
856 Collection<DescriptionElementBase> descriptionElements,
857 DescriptionBase targetDescription,
858 boolean isCopy,
859 boolean setNameInSource) {
860
861 UpdateResult result = new UpdateResult();
862 if (descriptionElements.isEmpty() || descriptionElements.iterator().next() == null){
863 result.setAbort();
864 return result;
865 }
866
867
868 if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
869 //if the descriptionElements collection is the elements set of a description, put it in a separate set before to avoid concurrent modification exceptions
870 descriptionElements = new HashSet<DescriptionElementBase>(descriptionElements);
871 // descriptionElementsTmp.addAll(descriptionElements);
872 // descriptionElements = descriptionElementsTmp;
873 }
874 for (DescriptionElementBase element : descriptionElements){
875 DescriptionBase<?> description = element.getInDescription();
876 description = HibernateProxyHelper.deproxy(dao.load(description.getUuid()));
877 Taxon taxon;
878 TaxonName name = null;
879 if (description instanceof TaxonDescription){
880 TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
881 if (taxonDescription.getTaxon() != null){
882 taxon = (Taxon) taxonDao.load(taxonDescription.getTaxon().getUuid());
883 name = taxon.getName();
884 }
885
886
887 }
888 DescriptionElementBase newElement = element.clone();
889 if (setNameInSource) {
890 for (DescriptionElementSource source: newElement.getSources()){
891 if (source.getNameUsedInSource() == null){
892 source.setNameUsedInSource(name);
893 }
894 }
895
896 }
897 targetDescription.addElement(newElement);
898 if (! isCopy){
899 description.removeElement(element);
900 dao.saveOrUpdate(description);
901 result.addUpdatedObject(description);
902 // if (description.getElements().isEmpty()){
903 // if (description instanceof TaxonDescription){
904 // TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
905 // if (taxDescription.getTaxon() != null){
906 // taxDescription.getTaxon().removeDescription((TaxonDescription)description);
907 // }
908 // }
909 // dao.delete(description);
910 //
911 // }//else{
912 // dao.saveOrUpdate(description);
913 // result.addUpdatedObject(description);
914 // }
915 }
916
917
918 }
919 dao.saveOrUpdate(targetDescription);
920 result.addUpdatedObject(targetDescription);
921 if (targetDescription instanceof TaxonDescription){
922 result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
923 }
924 return result;
925 }
926
927 // @Override
928 // @Transactional(readOnly = false)
929 // public UpdateResult moveDescriptionElementsToDescription(
930 // Set<UUID> descriptionElementUUIDs,
931 // UUID targetDescriptionUuid,
932 // boolean isCopy, boolean setNameInSource) {
933 // Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
934 // for(UUID deUuid : descriptionElementUUIDs) {
935 // DescriptionElementBase element = descriptionElementDao.load(deUuid);
936 // if (element != null){
937 // descriptionElements.add(element);
938 // }
939 // }
940 // DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
941 //
942 // return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
943 // }
944
945 @Override
946 @Transactional(readOnly = false)
947 public UpdateResult moveDescriptionElementsToDescription(
948 Set<UUID> descriptionElementUUIDs,
949 DescriptionBase targetDescription,
950 boolean isCopy, boolean setNameInSource) {
951 Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
952 for(UUID deUuid : descriptionElementUUIDs) {
953 DescriptionElementBase element = descriptionElementDao.load(deUuid);
954 if (element != null){
955 descriptionElements.add(element);
956 }
957 }
958 DescriptionBase newTargetDescription;
959 if (targetDescription.isPersisted()){
960 newTargetDescription = dao.load(targetDescription.getUuid());
961 }else{
962 if (targetDescription instanceof TaxonDescription){
963 Taxon taxon = (Taxon)taxonDao.load(((TaxonDescription)targetDescription).getTaxon().getUuid());
964
965 newTargetDescription = TaxonDescription.NewInstance(taxon, targetDescription.isImageGallery());
966
967 }else if (targetDescription instanceof TaxonNameDescription){
968 TaxonName name = nameDao.load(((TaxonNameDescription)targetDescription).getTaxonName().getUuid());
969 newTargetDescription = TaxonNameDescription.NewInstance(name);
970 }else {
971 SpecimenOrObservationBase specimen = occurrenceDao.load(((SpecimenDescription)targetDescription).getDescribedSpecimenOrObservation().getUuid());
972 newTargetDescription = SpecimenDescription.NewInstance(specimen);
973 }
974
975 newTargetDescription.addSources(targetDescription.getSources());
976 newTargetDescription.setTitleCache(targetDescription.getTitleCache(), targetDescription.isProtectedTitleCache());
977
978 }
979 return moveDescriptionElementsToDescription(descriptionElements, newTargetDescription, isCopy, setNameInSource);
980 }
981
982
983 @Override
984 @Transactional(readOnly = false)
985 public UpdateResult moveDescriptionElementsToDescription(
986 Set<UUID> descriptionElementUUIDs,
987 UUID targetTaxonUuid,
988 String moveMessage,
989 boolean isCopy, boolean setNameInSource, boolean useDefaultDescription, boolean createNewCurrentDeterminations) {
990 Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
991 TaxonDescription targetDescription = null;
992 if (useDefaultDescription && targetTaxon.hasDefaultDescription()) {
993 for (TaxonDescription des:targetTaxon.getDescriptions()) {
994 if (des.isDefault()) {
995 targetDescription = des;
996 break;
997 }
998 }
999 }
1000 if (targetDescription == null) {
1001 targetDescription = TaxonDescription.NewInstance(targetTaxon);
1002 }
1003 if (!targetTaxon.hasDefaultDescription()) {
1004 targetDescription.setDefault(true);
1005 }
1006 targetDescription.setTitleCache(moveMessage, true);
1007 Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
1008 annotation.setAnnotationType(AnnotationType.TECHNICAL());
1009 targetDescription.addAnnotation(annotation);
1010
1011 targetDescription = dao.save(targetDescription);
1012 Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
1013 for(UUID deUuid : descriptionElementUUIDs) {
1014 DescriptionElementBase descEl = descriptionElementDao.load(deUuid);
1015 descriptionElements.add(descEl);
1016 if (createNewCurrentDeterminations && descEl instanceof IndividualsAssociation && ((IndividualsAssociation)descEl).getAssociatedSpecimenOrObservation()!= null){
1017 SpecimenOrObservationBase specimen = HibernateProxyHelper.deproxy(((IndividualsAssociation)descEl).getAssociatedSpecimenOrObservation());
1018 DeterminationEvent event = specimen.getDeterminationsForTaxonOrName(targetTaxon, targetTaxon.getName());
1019 if (event != null) {
1020 specimen.setPreferredDetermination(event);
1021 }else {
1022 DeterminationEvent detEvent = DeterminationEvent.NewInstance(targetTaxon, specimen);
1023 specimen.setPreferredDetermination(detEvent);
1024 }
1025 }
1026 }
1027
1028 return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
1029 }
1030
1031 @Override
1032 public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
1033 Integer pageIndex){
1034 List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
1035 List<TermDto> subList = PagerUtils.pageList(results, pageIndex, pageSize);
1036 return new DefaultPagerImpl<>(pageIndex, Long.valueOf(results.size()), pageSize, subList);
1037 }
1038
1039
1040 @Override
1041 @Transactional(readOnly = false)
1042 public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon, boolean setNameInSource) {
1043 List<TaxonDescription> descriptions = new ArrayList<>(sourceTaxon.getDescriptions());
1044 UpdateResult result = new UpdateResult();
1045 result.addUpdatedObject(sourceTaxon);
1046 result.addUpdatedObject(targetTaxon);
1047 for(TaxonDescription description : descriptions){
1048 targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
1049 }
1050 return result;
1051 }
1052
1053 private TaxonDescription prepareDescriptionForMove(TaxonDescription description, Taxon sourceTaxon, boolean setNameInSource){
1054 String moveMessage = String.format("Description moved from %s", sourceTaxon);
1055 if(description.isProtectedTitleCache()){
1056 String separator = "";
1057 if(!StringUtils.isBlank(description.getTitleCache())){
1058 separator = " - ";
1059 }
1060 description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
1061 }
1062 else{
1063 description.setTitleCache(moveMessage, true);
1064 }
1065 Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
1066 annotation.setAnnotationType(AnnotationType.TECHNICAL());
1067 description.addAnnotation(annotation);
1068 if(setNameInSource){
1069 for (DescriptionElementBase element: description.getElements()){
1070 for (DescriptionElementSource source: element.getSources()){
1071 if (source.getNameUsedInSource() == null){
1072 source.setNameUsedInSource(sourceTaxon.getName());
1073 }
1074 }
1075 }
1076 }
1077 description.setDefault(false);
1078 return description;
1079 }
1080
1081 @Override
1082 @Transactional(readOnly = false)
1083 public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid, boolean setNameInSource) {
1084 Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
1085 Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
1086 return moveTaxonDescriptions(sourceTaxon, targetTaxon, setNameInSource);
1087
1088 }
1089
1090 @Override
1091 @Transactional(readOnly = false)
1092 public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid, boolean setNameInSource){
1093 TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
1094 Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
1095 Taxon sourceTaxon = description.getTaxon();
1096 UpdateResult result = new UpdateResult();
1097 result.addUpdatedObject(sourceTaxon);
1098 result.addUpdatedObject(targetTaxon);
1099
1100 targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
1101 return result;
1102
1103 }
1104
1105 @Override
1106 public DescriptionBaseDto loadDto(UUID descriptionUuid) {
1107 return dao.loadDto(descriptionUuid);
1108 }
1109
1110
1111 @Override
1112 public List<DescriptionBaseDto> loadDtos(Set<UUID> descriptionUuids) {
1113
1114 return dao.loadDtos(descriptionUuids);
1115 }
1116
1117 // FIXME Query should not be used in service layer
1118 @Override
1119 public List<DescriptionBaseDto> loadDtosForTaxon(UUID taxonUuid) {
1120 String sqlSelect = DescriptionBaseDto.getDescriptionBaseDtoForTaxonSelect();
1121 Query<Object[]> query = getSession().createQuery(sqlSelect, Object[].class);
1122 query.setParameter("uuid", taxonUuid);
1123
1124 List<Object[]> result = query.list();
1125 List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1126
1127 return list;
1128 }
1129
1130 @Override
1131 public TaxonNodeDto findTaxonNodeDtoForIndividualAssociation(UUID specimenUuid, UUID classificationUuid) {
1132 //get specimen used in description
1133 //get individial associations with this specimen
1134 //get taxon node for the classification
1135 List<SortableTaxonNodeQueryResult> result = dao.getNodeOfIndividualAssociationForSpecimen(specimenUuid, classificationUuid);
1136
1137 if (!result.isEmpty()){
1138 List<TaxonNodeDto> dtos = taxonNodeDao.createNodeDtos(result);
1139 if (dtos.size() == 1){
1140 return dtos.get(0);
1141 }else{
1142 logger.debug("There is more than one taxon associated to the specimen with uuid: " + specimenUuid + " return the first in the list");
1143 return dtos.get(0);
1144 }
1145 }
1146 return null;
1147 }
1148
1149 @Override
1150 @Transactional(readOnly = false)
1151 public UpdateResult moveDescriptionElementsToDescription(
1152 Set<UUID> descriptionElementUUIDs,
1153 UUID targetDescriptionUuid,
1154 boolean isCopy, boolean setNameInSource) {
1155 Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
1156 for(UUID deUuid : descriptionElementUUIDs) {
1157 DescriptionElementBase element = descriptionElementDao.load(deUuid);
1158 if (element != null){
1159 descriptionElements.add(element);
1160 }
1161 }
1162 DescriptionBase<?> targetDescription = dao.load(targetDescriptionUuid);
1163
1164 return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
1165 }
1166 }