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