Project

General

Profile

Download (54 KB) Statistics
| Branch: | Tag: | Revision:
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.log4j.Logger;
25
import org.hibernate.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.CategoricalDataDto;
34
import eu.etaxonomy.cdm.api.service.dto.DescriptionBaseDto;
35
import eu.etaxonomy.cdm.api.service.dto.DescriptionElementDto;
36
import eu.etaxonomy.cdm.api.service.dto.QuantitativeDataDto;
37
import eu.etaxonomy.cdm.api.service.dto.StateDataDto;
38
import eu.etaxonomy.cdm.api.service.dto.StatisticalMeasurementValueDto;
39
import eu.etaxonomy.cdm.api.service.dto.TaxonDistributionDTO;
40
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
41
import eu.etaxonomy.cdm.api.service.pager.Pager;
42
import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
43
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
44
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
45
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
46
import eu.etaxonomy.cdm.format.description.MicroFormatQuantitativeDescriptionBuilder;
47
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
48
import eu.etaxonomy.cdm.model.common.Annotation;
49
import eu.etaxonomy.cdm.model.common.AnnotationType;
50
import eu.etaxonomy.cdm.model.common.CdmBase;
51
import eu.etaxonomy.cdm.model.common.Language;
52
import eu.etaxonomy.cdm.model.common.Marker;
53
import eu.etaxonomy.cdm.model.common.MarkerType;
54
import eu.etaxonomy.cdm.model.description.CategoricalData;
55
import eu.etaxonomy.cdm.model.description.DescriptionBase;
56
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
57
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
58
import eu.etaxonomy.cdm.model.description.DescriptionType;
59
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
60
import eu.etaxonomy.cdm.model.description.Feature;
61
import eu.etaxonomy.cdm.model.description.MeasurementUnit;
62
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
63
import eu.etaxonomy.cdm.model.description.QuantitativeData;
64
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
65
import eu.etaxonomy.cdm.model.description.State;
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.TermDto;
98
import eu.etaxonomy.cdm.persistence.query.OrderHint;
99
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
100

    
101
/**
102
 * @author a.mueller
103
 * @author a.kohlbecker
104
 *
105
 * @since 24.06.2008
106
 */
107
@Service
108
@Transactional(readOnly = true)
109
public class DescriptionServiceImpl
110
        extends IdentifiableServiceBase<DescriptionBase,IDescriptionDao>
111
        implements IDescriptionService {
112

    
113
    private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
114

    
115
    protected IDescriptionElementDao descriptionElementDao;
116
    protected ITermTreeDao featureTreeDao;
117
    protected IDescriptiveDataSetDao descriptiveDataSetDao;
118
    protected ITermNodeDao termNodeDao;
119
    protected ITermVocabularyDao vocabularyDao;
120
    protected IDefinedTermDao definedTermDao;
121
    protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
122
    protected ITaxonDao taxonDao;
123
    protected ITaxonNameDao nameDao;
124
    protected IOccurrenceDao occurrenceDao;
125
    protected ITaxonNodeDao taxonNodeDao;
126
    protected IDescriptiveDataSetDao dataSetDao;
127
    protected ITermService termService;
128

    
129
    //TODO change to Interface
130
    private NaturalLanguageGenerator naturalLanguageGenerator;
131

    
132
    @Autowired
133
    protected void setFeatureTreeDao(ITermTreeDao featureTreeDao) {
134
        this.featureTreeDao = featureTreeDao;
135
    }
136

    
137
    @Autowired
138
    protected void setDescriptiveDataSetDao(IDescriptiveDataSetDao descriptiveDataSetDao) {
139
        this.descriptiveDataSetDao = descriptiveDataSetDao;
140
    }
141

    
142
    @Autowired
143
    protected void setTermNodeDao(ITermNodeDao featureNodeDao) {
144
        this.termNodeDao = featureNodeDao;
145
    }
146

    
147
    @Autowired
148
    protected void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
149
        this.vocabularyDao = vocabularyDao;
150
    }
151

    
152
    @Autowired
153
    protected void setDefinedTermDao(IDefinedTermDao definedTermDao) {
154
        this.definedTermDao = definedTermDao;
155
    }
156

    
157
    @Autowired
158
    protected void setTermService(ITermService definedTermService) {
159
        this.termService = definedTermService;
160
    }
161

    
162

    
163
    @Autowired
164
    protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao) {
165
        this.statisticalMeasurementValueDao = statisticalMeasurementValueDao;
166
    }
167

    
168
    @Autowired
169
    protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao) {
170
        this.descriptionElementDao = descriptionElementDao;
171
    }
172

    
173
    @Autowired
174
    protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator) {
175
        this.naturalLanguageGenerator = naturalLanguageGenerator;
176
    }
177

    
178
    @Autowired
179
    protected void setTaxonDao(ITaxonDao taxonDao) {
180
        this.taxonDao = taxonDao;
181
    }
182

    
183
    @Autowired
184
    protected void setTaxonNodeDao(ITaxonNodeDao taxonNodeDao) {
185
        this.taxonNodeDao = taxonNodeDao;
186
    }
187

    
188
    @Autowired
189
    protected void setDataSetDao(IDescriptiveDataSetDao dataSetDao) {
190
        this.dataSetDao = dataSetDao;
191
    }
192

    
193
    public DescriptionServiceImpl() {
194
        logger.debug("Load DescriptionService Bean");
195
    }
196

    
197
    @Override
198
    @Transactional(readOnly = false)
199
    public UpdateResult updateCaches(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
200
        if (clazz == null){
201
            clazz = DescriptionBase.class;
202
        }
203
        return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
204
    }
205

    
206
    @Override
207
    public TermVocabulary<Feature> getDefaultFeatureVocabulary(){
208
        String uuidFeature = "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
209
        UUID featureUuid = UUID.fromString(uuidFeature);
210
        return vocabularyDao.findByUuid(featureUuid);
211
    }
212

    
213
    @Override
214
    @Autowired
215
    protected void setDao(IDescriptionDao dao) {
216
        this.dao = dao;
217
    }
218

    
219
    @Override
220
    public long count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
221
        return dao.countDescriptions(type, hasImages, hasText, feature);
222
    }
223

    
224
    @Override
225
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
226
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
227

    
228
        List<T> results = listDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
229
        return new DefaultPagerImpl<>(pageNumber, Integer.valueOf(results.size()).longValue(), pageSize, results);
230
    }
231

    
232
    @Override
233
    @Deprecated
234
    public <T extends DescriptionElementBase> Pager<T> getDescriptionElements(DescriptionBase description,
235
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
236
        return pageDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
237
    }
238

    
239
    @Override
240
    public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
241
            Class<? extends DescriptionBase> descriptionType, Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber,
242
            List<String> propertyPaths) {
243

    
244
        long numberOfResults = dao.countDescriptionElements(description, descriptionType, features, type);
245
        List<T> results = new ArrayList<T>();
246
        if(AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)) {
247
            results = dao.getDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
248
        }
249
        return results;
250
    }
251

    
252
    @Override
253
    @Deprecated
254
    public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
255
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
256

    
257
        return listDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
258
    }
259

    
260
    @Override
261
    public Pager<Media> getMedia(DescriptionElementBase descriptionElement,	Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
262
        Long numberOfResults = descriptionElementDao.countMedia(descriptionElement);
263

    
264
        List<Media> results = new ArrayList<Media>();
265
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
266
            results = descriptionElementDao.getMedia(descriptionElement, pageSize, pageNumber, propertyPaths);
267
        }
268

    
269
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
270
    }
271

    
272
    @Override
273
    public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
274
        Set<MarkerType> markerTypes = null;
275
        Set<DescriptionType> descriptionTypes = null;
276
        return pageTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
277
    }
278

    
279
    @Override
280
    public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
281
        Set<MarkerType> markerTypes = null;
282
        Set<DescriptionType> descriptionTypes = null;
283
        return listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
284
    }
285

    
286
    @Override
287
    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) {
288
        long numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes);
289

    
290
        List<TaxonDescription> results = new ArrayList<>();
291
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
292
            results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
293
        }
294

    
295
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
296
    }
297

    
298
    @Override
299
    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) {
300
        List<TaxonDescription> results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
301
        return results;
302
    }
303

    
304

    
305
    @Override
306
    public List<Media> listTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths){
307
        return this.dao.listTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes, pageSize, pageNumber, propertyPaths);
308
    }
309

    
310
    @Override
311
    public int countTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes){
312
        return this.dao.countTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes);
313
    }
314

    
315
    @Override
316
    public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
317
        long numberOfResults = dao.countTaxonNameDescriptions(name);
318

    
319
        List<TaxonNameDescription> results = new ArrayList<>();
320
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
321
            results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
322
        }
323

    
324
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
325
    }
326

    
327

    
328
    @Override
329
    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) {
330
        long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
331

    
332
        @SuppressWarnings("rawtypes")
333
        List<DescriptionBase> results = new ArrayList<>();
334
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
335
            results = dao.listDescriptions(type, hasImages, hasText, feature, pageSize, pageNumber,orderHints,propertyPaths);
336
        }
337

    
338
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
339
    }
340

    
341
    /**
342
     * FIXME Candidate for harmonization
343
     * Rename: searchByDistribution
344
     */
345
    @Override
346
    public Pager<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm presence,	Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
347
        long numberOfResults = dao.countDescriptionByDistribution(namedAreas, presence);
348

    
349
        List<TaxonDescription> results = new ArrayList<>();
350
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
351
            results = dao.searchDescriptionByDistribution(namedAreas, presence, pageSize, pageNumber,orderHints,propertyPaths);
352
        }
353

    
354
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
355
    }
356

    
357
    /**
358
     * FIXME Candidate for harmonization
359
     * move: descriptionElementService.search
360
     */
361
    @Override
362
//    public Pager<T> searchElements(Class<? extends T> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
363
    public <S extends DescriptionElementBase> Pager<S> searchElements(Class<S> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
364
        long numberOfResults = descriptionElementDao.count(clazz, queryString);
365

    
366
        List<S> results = new ArrayList<>();
367
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
368
            results = (List<S>)descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
369
        }
370

    
371
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
372
    }
373

    
374
    @Override
375
    @Transactional(readOnly = false)
376
    public List<MergeResult<DescriptionBase>> mergeDescriptionElements(Collection<TaxonDistributionDTO> descriptionElements, boolean returnTransientEntity) {
377
        List<MergeResult<DescriptionBase>> mergedObjects = new ArrayList<>();
378

    
379
        for(TaxonDistributionDTO obj : descriptionElements) {
380
            Iterator<TaxonDescription> iterator = obj.getDescriptionsWrapper().getDescriptions().iterator();
381
            List<DescriptionBase> list = new ArrayList(obj.getDescriptionsWrapper().getDescriptions());
382
          //  Map<UUID, DescriptionBase> map = dao.saveOrUpdateAll(list);
383
//            MergeResult<DescriptionBase> mergeResult = new MergeResult<DescriptionBase>(mergedEntity, newEntities)
384
//            mergedObjects.add(map.values());
385
            while (iterator.hasNext()){
386
                TaxonDescription desc = iterator.next();
387
                mergedObjects.add(dao.merge(desc, returnTransientEntity));
388
            }
389
        }
390

    
391
        return mergedObjects;
392
    }
393

    
394
    @Override
395
    @Transactional(readOnly = false)
396
    public UpdateResult mergeDescriptions(Collection<DescriptionBaseDto> descriptions, UUID descriptiveDataSetUuid) {
397

    
398
        UpdateResult result = new UpdateResult();
399
        DescriptiveDataSet dataSet = descriptiveDataSetDao.load(descriptiveDataSetUuid);
400
        Set<DescriptionBase> descriptionsOfDataSet = dataSet.getDescriptions();
401
        HashMap<UUID, Set<DescriptionBase>> descriptionSpecimenMap = new HashMap<>();
402
        Set<DescriptionBase> specimenDescriptions;
403
        for (DescriptionBase<?> descriptionBase: descriptionsOfDataSet){
404
            if (descriptionBase.getDescribedSpecimenOrObservation() != null){
405
                specimenDescriptions = descriptionSpecimenMap.get(descriptionBase.getDescribedSpecimenOrObservation().getUuid());
406
                if (specimenDescriptions == null){
407
                    specimenDescriptions = new HashSet<>();
408
                }
409
                specimenDescriptions.add(descriptionBase);
410
                descriptionSpecimenMap.put(descriptionBase.getDescribedSpecimenOrObservation().getUuid(), specimenDescriptions);
411
            }
412
            if (descriptionBase instanceof TaxonDescription){
413
                specimenDescriptions = descriptionSpecimenMap.get(((TaxonDescription)descriptionBase).getTaxon().getUuid());
414
                if (specimenDescriptions == null){
415
                    specimenDescriptions = new HashSet<>();
416
                }
417
                specimenDescriptions.add(descriptionBase);
418
                descriptionSpecimenMap.put(((TaxonDescription)descriptionBase).getTaxon().getUuid(), specimenDescriptions);
419
            }
420
            if (descriptionBase instanceof TaxonNameDescription){
421
                specimenDescriptions = descriptionSpecimenMap.get(((TaxonNameDescription)descriptionBase).getTaxonName().getUuid());
422
                if (specimenDescriptions == null){
423
                    specimenDescriptions = new HashSet<>();
424
                }
425
                specimenDescriptions.add(descriptionBase);
426
                descriptionSpecimenMap.put(((TaxonNameDescription)descriptionBase).getTaxonName().getUuid(), specimenDescriptions);
427
            }
428
        }
429
        MergeResult<DescriptionBase> mergeResult = null;
430
        for(DescriptionBaseDto descDto : descriptions) {
431

    
432
            UUID descriptionUUID = descDto.getDescriptionUuid();
433
            DescriptionBase<?> description = load(descriptionUUID);
434

    
435
            UUID describedObjectUuid = null;
436
            if (description instanceof SpecimenDescription){
437
                describedObjectUuid = descDto.getSpecimenDto().getUuid();
438
            }else if (description instanceof TaxonDescription){
439
                describedObjectUuid = descDto.getTaxonDto().getUuid();
440
            }else if (description instanceof TaxonNameDescription){
441
                describedObjectUuid = descDto.getNameDto().getUuid();
442
            }
443

    
444
            Set<DescriptionBase> descSpecimen = descriptionSpecimenMap.get(describedObjectUuid);
445

    
446
            if (descSpecimen != null ){
447

    
448
//                TODO: elements are Dtos now, no cdm entities, needs to get the value and replace or create new description element
449
                Set<DescriptionElementDto> elements = new HashSet<>();
450
                for (Object element: descDto.getElements()){
451
                    elements.add((DescriptionElementDto)element);
452
                }
453

    
454
                DescriptionBase<?> desc = null;
455
                for (DescriptionBase<?> tempDesc: descSpecimen){
456
                    if (tempDesc.getUuid().equals(descDto.getDescriptionUuid())){
457
                        desc = tempDesc;
458
                        break;
459
                    }
460
                }
461

    
462
                Set<DescriptionElementBase> removeElements = new HashSet<>();
463
                Set<DescriptionElementBase> descriptionElements = desc.getElements();
464
                for (DescriptionElementBase elementBase: descriptionElements){
465
                    UUID descElementUuid = elementBase.getUuid();
466
                    if (descElementUuid != null){
467
                        List<DescriptionElementDto> equalUuidsElements = elements.stream().filter( e -> e != null && e.getElementUuid() != null && e.getElementUuid().equals(descElementUuid)).collect(Collectors.toList());
468
                        if (equalUuidsElements.size() == 0 || (equalUuidsElements.size() == 1 && equalUuidsElements.get(0)instanceof QuantitativeDataDto && ((QuantitativeDataDto)equalUuidsElements.get(0)).getValues().isEmpty())){
469
                            removeElements.add(elementBase);
470
                        }
471
                    }
472
                }
473
                if (!removeElements.isEmpty()){
474
                    for (DescriptionElementBase el: removeElements){
475
                        desc.removeElement(el);
476
                    }
477
                }
478

    
479
//                description.setDescribedSpecimenOrObservation(null);
480

    
481
                for (DescriptionElementDto descElement: elements){
482
                    if (descElement == null){
483
                        continue;
484
                    }
485
                    UUID descElementUuid = descElement.getElementUuid();
486
                    if (descElement instanceof CategoricalDataDto && ((CategoricalDataDto)descElement).getStates().isEmpty() || descElement instanceof QuantitativeDataDto && ((QuantitativeDataDto)descElement).getValues().isEmpty()){
487
                        continue;
488
                    }
489
                    List<DescriptionElementBase> equalUuidsElements = descriptionElements.stream().filter( e -> e.getUuid().equals(descElementUuid)).collect(Collectors.toList());
490
                    eu.etaxonomy.cdm.model.description.Feature feature =  DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Feature.class, descElement.getFeatureUuid());
491
                    if (feature == null){
492
                        feature = DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Character.class, descElement.getFeatureUuid());
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
                                State newState = DefinedTermBase.getTermByClassAndUUID(State.class, dataDto.getState().getUuid());
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
                                StatisticalMeasurementValue newStatisticalMeasurement = StatisticalMeasurementValue.NewInstance(DefinedTermBase.getTermByClassAndUUID(StatisticalMeasure.class, dataDto.getType().getUuid()), dataDto.getValue());
520
                                statisticalValues.add(newStatisticalMeasurement);
521
                                data.addStatisticalValue(newStatisticalMeasurement);
522
                            }
523

    
524
//                            data.getStatisticalValues().addAll(statisticalValues);
525
                            data = StructuredDescriptionAggregation.handleMissingMinOrMax(data,
526
                                    MissingMinimumMode.MinToZero, MissingMaximumMode.MaxToMin);
527
                            desc.addElement(data);
528
                        }
529

    
530
                        //create new element
531
                    }else{
532
                        DescriptionElementBase elementBase = equalUuidsElements.get(0);
533
                        if (elementBase.isInstanceOf(CategoricalData.class)){
534
                            CategoricalData data = HibernateProxyHelper.deproxy(elementBase, CategoricalData.class);
535
                            List<StateData> states = new ArrayList<>(data.getStateData());
536
                            List<StateDataDto> stateDtos = ((CategoricalDataDto)descElement).getStates();
537

    
538
                            data.getStateData().clear();
539
                            if (stateDtos.isEmpty()){
540
                                desc.removeElement(data);
541
                            }else{
542
                                for (StateDataDto dataDto: stateDtos){
543
                                        State newState = DefinedTermBase.getTermByClassAndUUID(State.class, dataDto.getState().getUuid());
544
                                        StateData newStateData = StateData.NewInstance(newState);
545
                                        data.addStateData(newStateData);
546
                                }
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
    @Override
672
    public DeleteResult isDeletable(UUID descriptionUuid){
673
        DeleteResult result = new DeleteResult();
674
        DescriptionBase<?> description = this.load(descriptionUuid);
675
        Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(description);
676

    
677
        if (references == null || references.isEmpty()){
678
            return result;
679
        }
680
        for (CdmBase ref: references){
681
            if (description instanceof TaxonDescription && ref instanceof Taxon && ref.equals(((TaxonDescription)description).getTaxon())){
682
                continue;
683
            } else if (description instanceof TaxonNameDescription && ref instanceof TaxonName && ref.equals(((TaxonNameDescription)description).getTaxonName())){
684
                continue;
685
            } else if (description instanceof SpecimenDescription && ref instanceof SpecimenOrObservationBase && ref.equals(((SpecimenDescription)description).getDescribedSpecimenOrObservation())){
686
                continue;
687
            } else if (ref instanceof DescriptionElementBase){
688
                continue;
689
            } else if (ref instanceof CdmLinkSource && ((CdmLinkSource)ref).hasNoTarget()) {
690
                continue; //maybe only workaround #9801
691
            }else {
692
                String message = "The description can't be completely deleted because it is referenced by " + ref.getUserFriendlyTypeName() ;
693
                result.setAbort();
694
                result.addException(new ReferencedObjectUndeletableException(message));
695
                result.addRelatedObject(ref);
696
            }
697
        }
698

    
699
        return result;
700
    }
701

    
702
    @Override
703
    @Deprecated
704
    public <T extends DescriptionElementBase> List<T> getDescriptionElementsForTaxon(
705
            Taxon taxon, Set<Feature> features,
706
            Class<T> type, Integer pageSize,
707
            Integer pageNumber, List<String> propertyPaths) {
708
        return listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
709
    }
710

    
711
    @Override
712
    public <T extends DescriptionElementBase> List<T> listDescriptionElementsForTaxon(
713
            Taxon taxon, Set<Feature> features,
714
            Class<T> type, Integer pageSize,
715
            Integer pageNumber, List<String> propertyPaths) {
716
        return dao.getDescriptionElementForTaxon(taxon.getUuid(), features, type, pageSize, pageNumber, propertyPaths);
717
    }
718

    
719
    @Override
720
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElementsForTaxon(
721
            Taxon taxon, Set<Feature> features,
722
            Class<T> type, Integer pageSize,
723
            Integer pageNumber, List<String> propertyPaths) {
724
        if (logger.isDebugEnabled()){logger.debug(" get count ...");}
725
        Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type);
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, pageSize, pageNumber, propertyPaths);
730
        } else {
731
            descriptionElements = new ArrayList<T>(0);
732
        }
733
        if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
734
        return new DefaultPagerImpl<T>(pageNumber, count, pageSize, descriptionElements);
735
    }
736

    
737
    @Override
738
    public String generateNaturalLanguageDescription(TermTree featureTree,
739
            TaxonDescription description, List<Language> preferredLanguages, String separator) {
740

    
741
        Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
742

    
743
        description = (TaxonDescription)load(description.getUuid());
744
        featureTree = featureTreeDao.load(featureTree.getUuid());
745

    
746
        StringBuilder naturalLanguageDescription = new StringBuilder();
747

    
748
        MarkerType useMarkerType = (MarkerType) definedTermDao.load(UUID.fromString("2e6e42d9-e92a-41f4-899b-03c0ac64f039"));
749
        boolean isUseDescription = false;
750
        if(!description.getMarkers().isEmpty()) {
751
            for (Marker marker: description.getMarkers()) {
752
                MarkerType markerType = marker.getMarkerType();
753
                if (markerType.equals(useMarkerType)) {
754
                    isUseDescription = true;
755
                }
756

    
757
            }
758
        }
759

    
760
        if(description.hasStructuredData() && !isUseDescription){
761

    
762

    
763
            String lastCategory = null;
764
            String categorySeparator = ". ";
765

    
766
            List<TextData> textDataList;
767
            TextData naturalLanguageDescriptionText = null;
768

    
769
            boolean useMicroFormatQuantitativeDescriptionBuilder = false;
770

    
771
            if(useMicroFormatQuantitativeDescriptionBuilder){
772

    
773
                MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
774
                naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
775
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
776

    
777
            } else {
778

    
779
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
780
                        featureTree,
781
                        (description),
782
                        lang);
783
            }
784

    
785
            return naturalLanguageDescriptionText.getText(lang);
786

    
787
//
788
//			boolean doItBetter = false;
789
//
790
//			for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
791
//				if(textData.getMultilanguageText().size() > 0){
792
//
793
//					if (!textData.getFeature().equals(Feature.UNKNOWN())) {
794
//						String featureLabel = textData.getFeature().getLabel(lang);
795
//
796
//						if(doItBetter){
797
//							/*
798
//							 *  WARNING
799
//							 *  The code lines below are desinged to handle
800
//							 *  a special case where as the feature label contains
801
//							 *  hierarchical information on the features. This code
802
//							 *  exist only as a base for discussion, and is not
803
//							 *  intendet to be used in production.
804
//							 */
805
//							featureLabel = StringUtils.remove(featureLabel, '>');
806
//
807
//							String[] labelTokens = StringUtils.split(featureLabel, '<');
808
//							if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
809
//								if(naturalLanguageDescription.length() > 0){
810
//									naturalLanguageDescription.append(separator);
811
//								}
812
//								naturalLanguageDescription.append(labelTokens[1]);
813
//							} else {
814
//								if(naturalLanguageDescription.length() > 0){
815
//									naturalLanguageDescription.append(categorySeparator);
816
//								}
817
//								naturalLanguageDescription.append(StringUtils.join(labelTokens));
818
//							}
819
//							lastCategory = labelTokens[0];
820
//							// end of demo code
821
//						} else {
822
//							if(naturalLanguageDescription.length() > 0){
823
//								naturalLanguageDescription.append(separator);
824
//							}
825
//							naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
826
//						}
827
//					} else {
828
//						if(naturalLanguageDescription.length() > 0){
829
//							naturalLanguageDescription.append(separator);
830
//						}
831
//					}
832
//					String text = textData.getMultilanguageText().values().iterator().next().getText();
833
//					naturalLanguageDescription.append(text);
834
//
835
//				}
836
//			}
837

    
838
        }
839
        else if (isUseDescription) {
840
            //AT: Left Blank in case we need to generate a Natural language text string.
841
        }
842
        return naturalLanguageDescription.toString();
843
    }
844

    
845

    
846
    @Override
847
    public boolean hasStructuredData(DescriptionBase<?> description) {
848
        return load(description.getUuid()).hasStructuredData();
849
    }
850

    
851

    
852
    @Override
853
   // @Transactional(readOnly = false)
854
    public UpdateResult moveDescriptionElementsToDescription(
855
            Collection<DescriptionElementBase> descriptionElements,
856
            DescriptionBase targetDescription,
857
            boolean isCopy,
858
            boolean setNameInSource) {
859

    
860
        UpdateResult result = new UpdateResult();
861
        if (descriptionElements.isEmpty() || descriptionElements.iterator().next() == null){
862
            result.setAbort();
863
            return result;
864
        }
865

    
866

    
867
        if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
868
            //if the descriptionElements collection is the elements set of a description, put it in a separate set before to avoid concurrent modification exceptions
869
            descriptionElements = new HashSet<DescriptionElementBase>(descriptionElements);
870
//			descriptionElementsTmp.addAll(descriptionElements);
871
//			descriptionElements = descriptionElementsTmp;
872
        }
873
        for (DescriptionElementBase element : descriptionElements){
874
            DescriptionBase<?> description = element.getInDescription();
875
            description = HibernateProxyHelper.deproxy(dao.load(description.getUuid()));
876
            Taxon taxon;
877
            TaxonName name = null;
878
            if (description instanceof TaxonDescription){
879
                TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
880
                if (taxonDescription.getTaxon() != null){
881
                    taxon = (Taxon) taxonDao.load(taxonDescription.getTaxon().getUuid());
882
                    name = taxon.getName();
883
                }
884

    
885

    
886
            }
887
            DescriptionElementBase newElement = element.clone();
888
            if (setNameInSource) {
889
                for (DescriptionElementSource source: newElement.getSources()){
890
                        if (source.getNameUsedInSource() == null){
891
                            source.setNameUsedInSource(name);
892
                        }
893
                    }
894

    
895
            }
896
            targetDescription.addElement(newElement);
897
            if (! isCopy){
898
                description.removeElement(element);
899
                dao.saveOrUpdate(description);
900
                result.addUpdatedObject(description);
901
//                if (description.getElements().isEmpty()){
902
//                   if (description instanceof TaxonDescription){
903
//                       TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
904
//                       if (taxDescription.getTaxon() != null){
905
//                           taxDescription.getTaxon().removeDescription((TaxonDescription)description);
906
//                       }
907
//                   }
908
//                    dao.delete(description);
909
//
910
//                }//else{
911
//                    dao.saveOrUpdate(description);
912
//                    result.addUpdatedObject(description);
913
//                }
914
            }
915

    
916

    
917
        }
918
        dao.saveOrUpdate(targetDescription);
919
        result.addUpdatedObject(targetDescription);
920
        if (targetDescription instanceof TaxonDescription){
921
            result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
922
        }
923
        return result;
924
    }
925

    
926
    @Override
927
    @Transactional(readOnly = false)
928
    public UpdateResult moveDescriptionElementsToDescription(
929
            Set<UUID> descriptionElementUUIDs,
930
            UUID targetDescriptionUuid,
931
            boolean isCopy, boolean setNameInSource) {
932
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
933
        for(UUID deUuid : descriptionElementUUIDs) {
934
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
935
            if (element != null){
936
                descriptionElements.add(element);
937
            }
938
        }
939
        DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
940

    
941
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
942
    }
943

    
944
    @Override
945
    @Transactional(readOnly = false)
946
    public UpdateResult moveDescriptionElementsToDescription(
947
            Set<UUID> descriptionElementUUIDs,
948
            DescriptionBase targetDescription,
949
            boolean isCopy, boolean setNameInSource) {
950
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
951
        for(UUID deUuid : descriptionElementUUIDs) {
952
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
953
            if (element != null){
954
                descriptionElements.add(element);
955
            }
956
        }
957
        DescriptionBase newTargetDescription;
958
        if (targetDescription.isPersited()){
959
            newTargetDescription = dao.load(targetDescription.getUuid());
960
        }else{
961
            if (targetDescription instanceof TaxonDescription){
962
                Taxon taxon = (Taxon)taxonDao.load(((TaxonDescription)targetDescription).getTaxon().getUuid());
963

    
964
                newTargetDescription = TaxonDescription.NewInstance(taxon, targetDescription.isImageGallery());
965

    
966
            }else if (targetDescription instanceof TaxonNameDescription){
967
                TaxonName name = nameDao.load(((TaxonNameDescription)targetDescription).getTaxonName().getUuid());
968
                newTargetDescription = TaxonNameDescription.NewInstance(name);
969
            }else {
970
                SpecimenOrObservationBase specimen = occurrenceDao.load(((SpecimenDescription)targetDescription).getDescribedSpecimenOrObservation().getUuid());
971
                newTargetDescription = SpecimenDescription.NewInstance(specimen);
972
            }
973

    
974
            newTargetDescription.addSources(targetDescription.getSources());
975
            newTargetDescription.setTitleCache(targetDescription.getTitleCache(), targetDescription.isProtectedTitleCache());
976

    
977
        }
978
        return moveDescriptionElementsToDescription(descriptionElements, newTargetDescription, isCopy, setNameInSource);
979
    }
980

    
981

    
982
    @Override
983
    @Transactional(readOnly = false)
984
    public UpdateResult moveDescriptionElementsToDescription(
985
            Set<UUID> descriptionElementUUIDs,
986
            UUID targetTaxonUuid,
987
            String moveMessage,
988
            boolean isCopy, boolean setNameInSource) {
989
        Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
990
        DescriptionBase targetDescription = TaxonDescription.NewInstance(targetTaxon);
991
        targetDescription.setTitleCache(moveMessage, true);
992
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
993
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
994
        targetDescription.addAnnotation(annotation);
995

    
996
        targetDescription = dao.save(targetDescription);
997
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
998
        for(UUID deUuid : descriptionElementUUIDs) {
999
            descriptionElements.add(descriptionElementDao.load(deUuid));
1000
        }
1001

    
1002
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
1003
    }
1004

    
1005
    @Override
1006
    public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
1007
            Integer pageIndex){
1008
        List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
1009
        List<TermDto> subList = PagerUtils.pageList(results, pageIndex, pageSize);
1010
        return new DefaultPagerImpl<TermDto>(pageIndex, results.size(), pageSize, subList);
1011
    }
1012

    
1013

    
1014
    @Override
1015
    @Transactional(readOnly = false)
1016
    public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon, boolean setNameInSource) {
1017
        List<TaxonDescription> descriptions = new ArrayList<>(sourceTaxon.getDescriptions());
1018
        UpdateResult result = new UpdateResult();
1019
        result.addUpdatedObject(sourceTaxon);
1020
        result.addUpdatedObject(targetTaxon);
1021
        for(TaxonDescription description : descriptions){
1022
            targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
1023
        }
1024
        return result;
1025
    }
1026

    
1027
    private TaxonDescription prepareDescriptionForMove(TaxonDescription description, Taxon sourceTaxon, boolean setNameInSource){
1028
        String moveMessage = String.format("Description moved from %s", sourceTaxon);
1029
        if(description.isProtectedTitleCache()){
1030
            String separator = "";
1031
            if(!StringUtils.isBlank(description.getTitleCache())){
1032
                separator = " - ";
1033
            }
1034
            description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
1035
        }
1036
        else{
1037
            description.setTitleCache(moveMessage, true);
1038
        }
1039
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
1040
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
1041
        description.addAnnotation(annotation);
1042
        if(setNameInSource){
1043
            for (DescriptionElementBase element: description.getElements()){
1044
                for (DescriptionElementSource source: element.getSources()){
1045
                    if (source.getNameUsedInSource() == null){
1046
                        source.setNameUsedInSource(sourceTaxon.getName());
1047
                    }
1048
                }
1049
            }
1050
        }
1051
        return description;
1052
    }
1053

    
1054
    @Override
1055
    @Transactional(readOnly = false)
1056
    public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid, boolean setNameInSource) {
1057
        Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
1058
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
1059
        return moveTaxonDescriptions(sourceTaxon, targetTaxon, setNameInSource);
1060

    
1061
    }
1062

    
1063
    @Override
1064
    @Transactional(readOnly = false)
1065
    public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid, boolean setNameInSource){
1066
        TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
1067
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
1068
        Taxon sourceTaxon = description.getTaxon();
1069
        UpdateResult result = new UpdateResult();
1070
        result.addUpdatedObject(sourceTaxon);
1071
        result.addUpdatedObject(targetTaxon);
1072

    
1073
        targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
1074
        return result;
1075

    
1076
    }
1077

    
1078
    @Override
1079
    public DescriptionBaseDto loadDto(UUID descriptionUuid) {
1080
        String sqlSelect =  DescriptionBaseDto.getDescriptionBaseDtoSelect();
1081
        Query query =  getSession().createQuery(sqlSelect);
1082
        query.setParameter("uuid", descriptionUuid);
1083

    
1084
        @SuppressWarnings("unchecked")
1085
        List<Object[]> result = query.list();
1086

    
1087
        List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1088

    
1089
        if (list.size()== 1){
1090
            DescriptionBaseDto dto = list.get(0);
1091
            //get categorical data
1092
            sqlSelect = CategoricalDataDto.getCategoricalDtoSelect();
1093
            query =  getSession().createQuery(sqlSelect);
1094
            query.setParameter("uuid", descriptionUuid);
1095
            @SuppressWarnings("unchecked")
1096
            List<Object[]>  resultCat = query.list();
1097
            List<CategoricalDataDto> listCategorical = CategoricalDataDto.categoricalDataDtoListFrom(resultCat);
1098

    
1099
            List<UUID> featureUuids = new ArrayList<>();
1100
            for (CategoricalDataDto catDto: listCategorical){
1101
                featureUuids.add(catDto.getFeatureUuid());
1102
            }
1103
            Map<UUID, TermDto> featureDtos = termService.findFeatureByUUIDsAsDtos(featureUuids);
1104
            for (CategoricalDataDto catDto: listCategorical){
1105
                FeatureDto featuredto = (FeatureDto)featureDtos.get(catDto.getFeatureUuid());
1106
                catDto.setFeatureDto(featuredto);
1107
            }
1108
            dto.getElements().addAll(listCategorical);
1109
            //get quantitative data
1110
            sqlSelect = QuantitativeDataDto.getQuantitativeDataDtoSelect();
1111
            query =  getSession().createQuery(sqlSelect);
1112
            query.setParameter("uuid", descriptionUuid);
1113
            @SuppressWarnings("unchecked")
1114
            List<Object[]>  resultQuant = query.list();
1115
            List<QuantitativeDataDto> listQuant = QuantitativeDataDto.quantitativeDataDtoListFrom(resultQuant);
1116
            dto.getElements().addAll(listQuant);
1117
            return dto;
1118
        }else{
1119
            return null;
1120
        }
1121

    
1122
    }
1123

    
1124
    @Override
1125
    public List<DescriptionBaseDto> loadDtosForTaxon(UUID taxonUuid) {
1126
        String sqlSelect =  DescriptionBaseDto.getDescriptionBaseDtoForTaxonSelect();
1127
        Query query =  getSession().createQuery(sqlSelect);
1128
        query.setParameter("uuid", taxonUuid);
1129

    
1130
        @SuppressWarnings("unchecked")
1131
        List<Object[]> result = query.list();
1132

    
1133
        List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1134

    
1135
        return list;
1136

    
1137
    }
1138

    
1139

    
1140
}
(12-12/95)