Project

General

Profile

Download (54.5 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.MergeResult;
96
import eu.etaxonomy.cdm.persistence.dto.TermDto;
97
import eu.etaxonomy.cdm.persistence.query.OrderHint;
98
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
99

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

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

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

    
127
    //TODO change to Interface
128
    private NaturalLanguageGenerator naturalLanguageGenerator;
129

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

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

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

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

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

    
155
    @Autowired
156
    protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao) {
157
        this.statisticalMeasurementValueDao = statisticalMeasurementValueDao;
158
    }
159

    
160
    @Autowired
161
    protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao) {
162
        this.descriptionElementDao = descriptionElementDao;
163
    }
164

    
165
    @Autowired
166
    protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator) {
167
        this.naturalLanguageGenerator = naturalLanguageGenerator;
168
    }
169

    
170
    @Autowired
171
    protected void setTaxonDao(ITaxonDao taxonDao) {
172
        this.taxonDao = taxonDao;
173
    }
174

    
175
    @Autowired
176
    protected void setTaxonNodeDao(ITaxonNodeDao taxonNodeDao) {
177
        this.taxonNodeDao = taxonNodeDao;
178
    }
179

    
180
    @Autowired
181
    protected void setDataSetDao(IDescriptiveDataSetDao dataSetDao) {
182
        this.dataSetDao = dataSetDao;
183
    }
184

    
185
    public DescriptionServiceImpl() {
186
        logger.debug("Load DescriptionService Bean");
187
    }
188

    
189
    @Override
190
    @Transactional(readOnly = false)
191
    public UpdateResult updateCaches(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
192
        if (clazz == null){
193
            clazz = DescriptionBase.class;
194
        }
195
        return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
196
    }
197

    
198
    @Override
199
    public TermVocabulary<Feature> getDefaultFeatureVocabulary(){
200
        String uuidFeature = "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
201
        UUID featureUuid = UUID.fromString(uuidFeature);
202
        return vocabularyDao.findByUuid(featureUuid);
203
    }
204

    
205
    @Override
206
    @Autowired
207
    protected void setDao(IDescriptionDao dao) {
208
        this.dao = dao;
209
    }
210

    
211
    @Override
212
    public long count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
213
        return dao.countDescriptions(type, hasImages, hasText, feature);
214
    }
215

    
216
    @Override
217
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
218
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
219

    
220
        List<T> results = listDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
221
        return new DefaultPagerImpl<>(pageNumber, Integer.valueOf(results.size()).longValue(), pageSize, results);
222
    }
223

    
224
    @Override
225
    @Deprecated
226
    public <T extends DescriptionElementBase> Pager<T> getDescriptionElements(DescriptionBase description,
227
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
228
        return pageDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
229
    }
230

    
231
    @Override
232
    public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
233
            Class<? extends DescriptionBase> descriptionType, Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber,
234
            List<String> propertyPaths) {
235

    
236
        long numberOfResults = dao.countDescriptionElements(description, descriptionType, features, type);
237
        List<T> results = new ArrayList<T>();
238
        if(AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)) {
239
            results = dao.getDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
240
        }
241
        return results;
242
    }
243

    
244
    @Override
245
    @Deprecated
246
    public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
247
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
248

    
249
        return listDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
250
    }
251

    
252
    @Override
253
    public Pager<Annotation> getDescriptionElementAnnotations(DescriptionElementBase annotatedObj, MarkerType status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
254
        long numberOfResults = descriptionElementDao.countAnnotations(annotatedObj, status);
255

    
256
        List<Annotation> results = new ArrayList<>();
257
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
258
            results = descriptionElementDao.getAnnotations(annotatedObj, status, pageSize, pageNumber, orderHints, propertyPaths);
259
        }
260

    
261
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
262
    }
263

    
264

    
265
    @Override
266
    public Pager<Media> getMedia(DescriptionElementBase descriptionElement,	Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
267
        Long numberOfResults = descriptionElementDao.countMedia(descriptionElement);
268

    
269
        List<Media> results = new ArrayList<Media>();
270
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
271
            results = descriptionElementDao.getMedia(descriptionElement, pageSize, pageNumber, propertyPaths);
272
        }
273

    
274
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
275
    }
276

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

    
284
    @Override
285
    public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
286
        Set<MarkerType> markerTypes = null;
287
        Set<DescriptionType> descriptionTypes = null;
288
        return listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
289
    }
290

    
291
    @Override
292
    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) {
293
        long numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes);
294

    
295
        List<TaxonDescription> results = new ArrayList<>();
296
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
297
            results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
298
        }
299

    
300
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
301
    }
302

    
303
    @Override
304
    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) {
305
        List<TaxonDescription> results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
306
        return results;
307
    }
308

    
309

    
310
    @Override
311
    public List<Media> listTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths){
312
        return this.dao.listTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes, pageSize, pageNumber, propertyPaths);
313
    }
314

    
315
    @Override
316
    public int countTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes){
317
        return this.dao.countTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes);
318
    }
319

    
320
    @Override
321
    public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
322
        long numberOfResults = dao.countTaxonNameDescriptions(name);
323

    
324
        List<TaxonNameDescription> results = new ArrayList<>();
325
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
326
            results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
327
        }
328

    
329
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
330
    }
331

    
332

    
333
    @Override
334
    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) {
335
        long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
336

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

    
343
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
344
    }
345

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

    
354
        List<TaxonDescription> results = new ArrayList<>();
355
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
356
            results = dao.searchDescriptionByDistribution(namedAreas, presence, pageSize, pageNumber,orderHints,propertyPaths);
357
        }
358

    
359
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
360
    }
361

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

    
371
        List<S> results = new ArrayList<>();
372
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
373
            results = (List<S>)descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
374
        }
375

    
376
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
377
    }
378

    
379
    /**
380
     * FIXME Candidate for harmonization
381
     * descriptionElementService.find
382
     */
383
    @Override
384
    public DescriptionElementBase getDescriptionElementByUuid(UUID uuid) {
385
        return descriptionElementDao.findByUuid(uuid);
386
    }
387

    
388
    /**
389
     * FIXME Candidate for harmonization
390
     * descriptionElementService.load
391
     */
392
    @Override
393
    public DescriptionElementBase loadDescriptionElement(UUID uuid,	List<String> propertyPaths) {
394
        return descriptionElementDao.load(uuid, propertyPaths);
395
    }
396

    
397
    /**
398
     * FIXME Candidate for harmonization
399
     * descriptionElementService.save
400
     */
401
    @Override
402
    @Transactional(readOnly = false)
403
    public UUID saveDescriptionElement(DescriptionElementBase descriptionElement) {
404
        return descriptionElementDao.save(descriptionElement).getUuid();
405
    }
406

    
407
    /**
408
     * FIXME Candidate for harmonization
409
     * descriptionElementService.save
410
     */
411
    @Override
412
    @Transactional(readOnly = false)
413
    public Map<UUID, DescriptionElementBase> saveDescriptionElement(Collection<DescriptionElementBase> descriptionElements) {
414
        return descriptionElementDao.saveAll(descriptionElements);
415
    }
416

    
417
    @Override
418
    @Transactional(readOnly = false)
419
    public List<MergeResult<DescriptionBase>> mergeDescriptionElements(Collection<TaxonDistributionDTO> descriptionElements, boolean returnTransientEntity) {
420
        List<MergeResult<DescriptionBase>> mergedObjects = new ArrayList<>();
421

    
422
        for(TaxonDistributionDTO obj : descriptionElements) {
423
            Iterator<TaxonDescription> iterator = obj.getDescriptionsWrapper().getDescriptions().iterator();
424
            List<DescriptionBase> list = new ArrayList(obj.getDescriptionsWrapper().getDescriptions());
425
          //  Map<UUID, DescriptionBase> map = dao.saveOrUpdateAll(list);
426
//            MergeResult<DescriptionBase> mergeResult = new MergeResult<DescriptionBase>(mergedEntity, newEntities)
427
//            mergedObjects.add(map.values());
428
            while (iterator.hasNext()){
429
                TaxonDescription desc = iterator.next();
430
                mergedObjects.add(dao.merge(desc, returnTransientEntity));
431
            }
432
        }
433

    
434
        return mergedObjects;
435
    }
436

    
437
    @Override
438
    @Transactional(readOnly = false)
439
    public UpdateResult mergeDescriptions(Collection<DescriptionBaseDto> descriptions, UUID descriptiveDataSetUuid) {
440

    
441
        UpdateResult result = new UpdateResult();
442
        DescriptiveDataSet dataSet = descriptiveDataSetDao.load(descriptiveDataSetUuid);
443
        Set<DescriptionBase> descriptionsOfDataSet = dataSet.getDescriptions();
444
        HashMap<UUID, Set<DescriptionBase>> descriptionSpecimenMap = new HashMap<>();
445
        Set<DescriptionBase> specimenDescriptions;
446
        for (DescriptionBase<?> descriptionBase: descriptionsOfDataSet){
447
            if (descriptionBase.getDescribedSpecimenOrObservation() != null){
448
                specimenDescriptions = descriptionSpecimenMap.get(descriptionBase.getDescribedSpecimenOrObservation().getUuid());
449
                if (specimenDescriptions == null){
450
                    specimenDescriptions = new HashSet<>();
451
                }
452
                specimenDescriptions.add(descriptionBase);
453
                descriptionSpecimenMap.put(descriptionBase.getDescribedSpecimenOrObservation().getUuid(), specimenDescriptions);
454
            }
455
            if (descriptionBase instanceof TaxonDescription){
456
                specimenDescriptions = descriptionSpecimenMap.get(((TaxonDescription)descriptionBase).getTaxon().getUuid());
457
                if (specimenDescriptions == null){
458
                    specimenDescriptions = new HashSet<>();
459
                }
460
                specimenDescriptions.add(descriptionBase);
461
                descriptionSpecimenMap.put(((TaxonDescription)descriptionBase).getTaxon().getUuid(), specimenDescriptions);
462
            }
463
            if (descriptionBase instanceof TaxonNameDescription){
464
                specimenDescriptions = descriptionSpecimenMap.get(((TaxonNameDescription)descriptionBase).getTaxonName().getUuid());
465
                if (specimenDescriptions == null){
466
                    specimenDescriptions = new HashSet<>();
467
                }
468
                specimenDescriptions.add(descriptionBase);
469
                descriptionSpecimenMap.put(((TaxonNameDescription)descriptionBase).getTaxonName().getUuid(), specimenDescriptions);
470
            }
471
        }
472
        MergeResult<DescriptionBase> mergeResult = null;
473
        for(DescriptionBaseDto descDto : descriptions) {
474

    
475
            UUID descriptionUUID = descDto.getDescriptionUuid();
476
            DescriptionBase<?> description = load(descriptionUUID);
477

    
478
            UUID describedObjectUuid = null;
479
            if (description instanceof SpecimenDescription){
480
                describedObjectUuid = descDto.getSpecimenDto().getUuid();
481
            }else if (description instanceof TaxonDescription){
482
                describedObjectUuid = descDto.getTaxonDto().getUuid();
483
            }else if (description instanceof TaxonNameDescription){
484
                describedObjectUuid = descDto.getNameDto().getUuid();
485
            }
486

    
487
            Set<DescriptionBase> descSpecimen = descriptionSpecimenMap.get(describedObjectUuid);
488

    
489

    
490

    
491
            if (descSpecimen != null ){
492

    
493
//                TODO: elements are Dtos now, no cdm entities, needs to get the value and replace or create new description element
494
                Set<DescriptionElementDto> elements = new HashSet<>();
495
                for (Object element: descDto.getElements()){
496
                    elements.add((DescriptionElementDto)element);
497
                }
498

    
499
                DescriptionBase desc = null;
500
                for (DescriptionBase tempDesc: descSpecimen){
501
                    if (tempDesc.getUuid().equals(descDto.getDescriptionUuid())){
502
                        desc = tempDesc;
503
                        break;
504
                    }
505
                }
506

    
507
                Set<DescriptionElementBase> removeElements = new HashSet<>();
508
                Set<DescriptionElementBase> descriptionElements = desc.getElements();
509
                for (DescriptionElementBase elementBase: descriptionElements){
510
                    UUID descElementUuid = elementBase.getUuid();
511
                    if (descElementUuid != null){
512
                        List<DescriptionElementDto> equalUuidsElements = elements.stream().filter( e -> e != null && e.getElementUuid() != null && e.getElementUuid().equals(descElementUuid)).collect(Collectors.toList());
513
                        if (equalUuidsElements.size() == 0 || (equalUuidsElements.size() == 1 && equalUuidsElements.get(0)instanceof QuantitativeDataDto && ((QuantitativeDataDto)equalUuidsElements.get(0)).getValues().isEmpty())){
514
                            removeElements.add(elementBase);
515
                        }
516
                    }
517
                }
518
                if (!removeElements.isEmpty()){
519
                    for (DescriptionElementBase el: removeElements){
520
                        desc.removeElement(el);
521
                    }
522
                }
523

    
524
//                description.setDescribedSpecimenOrObservation(null);
525

    
526
                for (DescriptionElementDto descElement: elements){
527
                    UUID descElementUuid = descElement.getElementUuid();
528
                    if (descElement instanceof CategoricalDataDto && ((CategoricalDataDto)descElement).getStates().isEmpty() || descElement instanceof QuantitativeDataDto && ((QuantitativeDataDto)descElement).getValues().isEmpty()){
529
                        continue;
530
                    }
531
                    List<DescriptionElementBase> equalUuidsElements = descriptionElements.stream().filter( e -> e.getUuid().equals(descElementUuid)).collect(Collectors.toList());
532
                    eu.etaxonomy.cdm.model.description.Feature feature =  DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Feature.class, descElement.getFeatureUuid());
533
                    if (feature == null){
534
                        feature = DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Character.class, descElement.getFeatureUuid());
535
                    }
536
                    if (equalUuidsElements.size() == 0){
537
                        if (descElement instanceof CategoricalDataDto){
538

    
539
                            CategoricalData elementBase = CategoricalData.NewInstance(feature);
540
                            List<StateDataDto> stateDtos = ((CategoricalDataDto)descElement).getStates();
541
                            for (StateDataDto dataDto: stateDtos){
542
                                //create new statedata
543
                                State newState = DefinedTermBase.getTermByClassAndUUID(State.class, dataDto.getState().getUuid());
544
                                StateData newStateData = StateData.NewInstance(newState);
545
                                elementBase.addStateData(newStateData);
546
                            }
547
                            desc.addElement(elementBase);
548
                        }
549
                        if (descElement instanceof QuantitativeDataDto){
550

    
551
                            QuantitativeData data = QuantitativeData.NewInstance(feature);
552
                            if (((QuantitativeDataDto) descElement).getMeasurementUnit() != null){
553
                                MeasurementUnit unit = DefinedTermBase.getTermByClassAndUUID(MeasurementUnit.class, ((QuantitativeDataDto) descElement).getMeasurementUnit().getUuid());
554
                                data.setUnit(unit);
555
                            }
556
                            Set<StatisticalMeasurementValue> statisticalValues = new HashSet<>();
557
                            Set<StatisticalMeasurementValueDto> valueDtos = ((QuantitativeDataDto)descElement).getValues();
558
                            data.getStatisticalValues().clear();
559
                            for (StatisticalMeasurementValueDto dataDto: valueDtos){
560
                                //create new statedata
561
                                StatisticalMeasurementValue newStatisticalMeasurement = StatisticalMeasurementValue.NewInstance(DefinedTermBase.getTermByClassAndUUID(StatisticalMeasure.class, dataDto.getType().getUuid()), dataDto.getValue());
562
                                statisticalValues.add(newStatisticalMeasurement);
563
                                data.addStatisticalValue(newStatisticalMeasurement);
564
                            }
565

    
566
//                            data.getStatisticalValues().addAll(statisticalValues);
567
                            data = StructuredDescriptionAggregation.handleMissingMinOrMax(data,
568
                                    MissingMinimumMode.MinToZero, MissingMaximumMode.MaxToMin);
569
                            desc.addElement(data);
570
                        }
571

    
572
                        //create new element
573
                    }else{
574
                        DescriptionElementBase elementBase = equalUuidsElements.get(0);
575
                        if (elementBase.isInstanceOf(CategoricalData.class)){
576
                            CategoricalData data = HibernateProxyHelper.deproxy(elementBase, CategoricalData.class);
577
                            List<StateData> states = new ArrayList<>(data.getStateData());
578
                            List<StateDataDto> stateDtos = ((CategoricalDataDto)descElement).getStates();
579

    
580
                            data.getStateData().clear();
581
                            if (stateDtos.isEmpty()){
582
                                desc.removeElement(data);
583
                            }else{
584
                                for (StateDataDto dataDto: stateDtos){
585
                                        State newState = DefinedTermBase.getTermByClassAndUUID(State.class, dataDto.getState().getUuid());
586
                                        StateData newStateData = StateData.NewInstance(newState);
587
                                        data.addStateData(newStateData);
588
                                }
589
                            }
590

    
591
                        }else if (elementBase.isInstanceOf(QuantitativeData.class)){
592
                            QuantitativeData data = HibernateProxyHelper.deproxy(elementBase, QuantitativeData.class);
593

    
594
                            Set<StatisticalMeasurementValue> statisticalValues = new HashSet<>();
595
                            if (((QuantitativeDataDto) descElement).getMeasurementUnit() != null){
596
                                MeasurementUnit unit = DefinedTermBase.getTermByClassAndUUID(MeasurementUnit.class, ((QuantitativeDataDto) descElement).getMeasurementUnit().getUuid());
597
                                if (data.getUnit() == null || (data.getUnit() != null && !data.getUnit().equals(unit))){
598
                                    data.setUnit(unit);
599
                                }
600
                            }
601
                            Set<StatisticalMeasurementValueDto> valueDtos = ((QuantitativeDataDto)descElement).getValues();
602
                            data.getStatisticalValues().clear();
603
                            if (valueDtos.isEmpty()){
604
                                desc.removeElement(data);
605
                            }else{
606
                                for (StatisticalMeasurementValueDto dataDto: valueDtos){
607
                                    //create new statedata
608
                                    StatisticalMeasure statMeasure = DefinedTermBase.getTermByClassAndUUID(StatisticalMeasure.class, dataDto.getType().getUuid());
609

    
610
                                    StatisticalMeasurementValue newStatisticalMeasurement = StatisticalMeasurementValue.NewInstance(statMeasure, dataDto.getValue());
611
                                    statisticalValues.add(newStatisticalMeasurement);
612
                                    data.addStatisticalValue(newStatisticalMeasurement);
613
                                }
614

    
615
    //                            data.getStatisticalValues().addAll(statisticalValues);
616
                                data = StructuredDescriptionAggregation.handleMissingMinOrMax(data,
617
                                        MissingMinimumMode.MinToZero, MissingMaximumMode.MaxToMin);
618
                            }
619

    
620
                        }
621
                    }
622
                  //remove deleted elements
623

    
624
                }
625

    
626
                descriptionSpecimenMap.get(describedObjectUuid).add(desc);
627

    
628
                description = desc;
629
            }
630
            try{
631
                if (description != null){
632
                    mergeResult = dao.merge(description, true);
633
                    result.addUpdatedObject( mergeResult.getMergedEntity());
634
                }
635

    
636
//                if (description instanceof SpecimenDescription){
637
//                    result.addUpdatedObject(mergeResult.getMergedEntity().getDescribedSpecimenOrObservation());
638
//                }else if (description instanceof TaxonDescription){
639
//                    result.addUpdatedObject(((TaxonDescription)mergeResult.getMergedEntity()).getTaxon());
640
//                }else if (description instanceof TaxonNameDescription){
641
//                    result.addUpdatedObject(((TaxonNameDescription)mergeResult.getMergedEntity()).getTaxonName());
642
//                }
643
            }catch(Exception e){
644
                e.printStackTrace();
645
            }
646

    
647
        }
648

    
649
        return result;
650
    }
651

    
652
    /**
653
     * FIXME Candidate for harmonization
654
     * descriptionElementService.delete
655
     */
656
    @Override
657
    public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
658
        return descriptionElementDao.delete(descriptionElement);
659
    }
660

    
661
    @Override
662
    public UUID deleteDescriptionElement(UUID descriptionElementUuid) {
663
        return deleteDescriptionElement(descriptionElementDao.load(descriptionElementUuid));
664
    }
665

    
666
    @Override
667
    @Transactional(readOnly = false)
668
    public DeleteResult deleteDescription(DescriptionBase<?> description) {
669

    
670
        DeleteResult deleteResult = new DeleteResult();
671
        if (description == null){
672
            return deleteResult;
673
        }
674
        //avoid lazy init exception
675
        description = load(description.getId(), Arrays.asList("descriptiveDataSets"));
676

    
677
        deleteResult = isDeletable(description.getUuid());
678
        if (deleteResult.getRelatedObjects() != null && deleteResult.getRelatedObjects().size() == 1){
679
            Iterator<CdmBase> relObjects = deleteResult.getRelatedObjects().iterator();
680
            CdmBase next = relObjects.next();
681
            if (next instanceof CdmLinkSource){
682
                CdmLinkSource source = (CdmLinkSource)next;
683
                ICdmTarget target = source.getTarget();
684

    
685

    
686
            }
687
        }
688
        if (deleteResult.isOk() ){
689
            CdmBase.deproxy(description);
690
        	if (description instanceof TaxonDescription){
691
        		TaxonDescription taxDescription = (TaxonDescription)description;
692
        		Taxon tax = taxDescription.getTaxon();
693
        		if (tax != null){
694
        		    tax.removeDescription(taxDescription, true);
695
        		    deleteResult.addUpdatedObject(tax);
696
        		}
697
        	}
698
        	else if (description instanceof SpecimenDescription){
699
        	    SpecimenDescription specimenDescription = (SpecimenDescription)description;
700
        	    SpecimenOrObservationBase<?> specimen = specimenDescription.getDescribedSpecimenOrObservation();
701
        	    if (specimen != null){
702
        	        specimen.removeDescription(specimenDescription);
703
        	        deleteResult.addUpdatedObject(specimen);
704
        	    }
705
        	}
706

    
707
        	for (DescriptiveDataSet dataset : description.getDescriptiveDataSets()) {
708
        	    dataset.removeDescription(description);
709
            }
710

    
711
        	dao.delete(description);
712
        	deleteResult.addDeletedObject(description);
713
        	deleteResult.setCdmEntity(description);
714
        }else{
715
            logger.info(deleteResult.getExceptions().toString());
716
        }
717

    
718
        return deleteResult;
719
    }
720

    
721
    @Override
722
    @Transactional(readOnly = false)
723
    public DeleteResult deleteDescription(UUID descriptionUuid) {
724
        return deleteDescription(dao.load(descriptionUuid));
725
    }
726

    
727
    @Override
728
    public DeleteResult isDeletable(UUID descriptionUuid){
729
        DeleteResult result = new DeleteResult();
730
        DescriptionBase<?> description = this.load(descriptionUuid);
731
        Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(description);
732

    
733
        if (references == null || references.isEmpty()){
734
            return result;
735
        }
736
        for (CdmBase ref: references){
737
            if (description instanceof TaxonDescription && ref instanceof Taxon && ref.equals(((TaxonDescription)description).getTaxon())){
738
                continue;
739
            } else if (description instanceof TaxonNameDescription && ref instanceof TaxonName && ref.equals(((TaxonNameDescription)description).getTaxonName())){
740
                continue;
741
            } else if (description instanceof SpecimenDescription && ref instanceof SpecimenOrObservationBase && ref.equals(((SpecimenDescription)description).getDescribedSpecimenOrObservation())){
742
                continue;
743
            } else if (ref instanceof DescriptionElementBase){
744
                continue;
745
            } else if (ref instanceof CdmLinkSource && ((CdmLinkSource)ref).hasNoTarget()) {
746
                continue; //maybe only workaround #9801
747
            }else {
748
                String message = "The description can't be completely deleted because it is referenced by " + ref.getUserFriendlyTypeName() ;
749
                result.setAbort();
750
                result.addException(new ReferencedObjectUndeletableException(message));
751
                result.addRelatedObject(ref);
752
            }
753
        }
754

    
755
        return result;
756
    }
757

    
758
    @Override
759
    @Deprecated
760
    public <T extends DescriptionElementBase> List<T> getDescriptionElementsForTaxon(
761
            Taxon taxon, Set<Feature> features,
762
            Class<T> type, Integer pageSize,
763
            Integer pageNumber, List<String> propertyPaths) {
764
        return listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
765
    }
766

    
767
    @Override
768
    public <T extends DescriptionElementBase> List<T> listDescriptionElementsForTaxon(
769
            Taxon taxon, Set<Feature> features,
770
            Class<T> type, Integer pageSize,
771
            Integer pageNumber, List<String> propertyPaths) {
772
        return dao.getDescriptionElementForTaxon(taxon.getUuid(), features, type, pageSize, pageNumber, propertyPaths);
773
    }
774

    
775
    @Override
776
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElementsForTaxon(
777
            Taxon taxon, Set<Feature> features,
778
            Class<T> type, Integer pageSize,
779
            Integer pageNumber, List<String> propertyPaths) {
780
        if (logger.isDebugEnabled()){logger.debug(" get count ...");}
781
        Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type);
782
        List<T> descriptionElements;
783
        if(AbstractPagerImpl.hasResultsInRange(count, pageNumber, pageSize)){ // no point checking again
784
            if (logger.isDebugEnabled()){logger.debug(" get list ...");}
785
            descriptionElements = listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
786
        } else {
787
            descriptionElements = new ArrayList<T>(0);
788
        }
789
        if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
790
        return new DefaultPagerImpl<T>(pageNumber, count, pageSize, descriptionElements);
791
    }
792

    
793
    @Override
794
    public String generateNaturalLanguageDescription(TermTree featureTree,
795
            TaxonDescription description, List<Language> preferredLanguages, String separator) {
796

    
797
        Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
798

    
799
        description = (TaxonDescription)load(description.getUuid());
800
        featureTree = featureTreeDao.load(featureTree.getUuid());
801

    
802
        StringBuilder naturalLanguageDescription = new StringBuilder();
803

    
804
        MarkerType useMarkerType = (MarkerType) definedTermDao.load(UUID.fromString("2e6e42d9-e92a-41f4-899b-03c0ac64f039"));
805
        boolean isUseDescription = false;
806
        if(!description.getMarkers().isEmpty()) {
807
            for (Marker marker: description.getMarkers()) {
808
                MarkerType markerType = marker.getMarkerType();
809
                if (markerType.equals(useMarkerType)) {
810
                    isUseDescription = true;
811
                }
812

    
813
            }
814
        }
815

    
816
        if(description.hasStructuredData() && !isUseDescription){
817

    
818

    
819
            String lastCategory = null;
820
            String categorySeparator = ". ";
821

    
822
            List<TextData> textDataList;
823
            TextData naturalLanguageDescriptionText = null;
824

    
825
            boolean useMicroFormatQuantitativeDescriptionBuilder = false;
826

    
827
            if(useMicroFormatQuantitativeDescriptionBuilder){
828

    
829
                MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
830
                naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
831
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
832

    
833
            } else {
834

    
835
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
836
                        featureTree,
837
                        (description),
838
                        lang);
839
            }
840

    
841
            return naturalLanguageDescriptionText.getText(lang);
842

    
843
//
844
//			boolean doItBetter = false;
845
//
846
//			for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
847
//				if(textData.getMultilanguageText().size() > 0){
848
//
849
//					if (!textData.getFeature().equals(Feature.UNKNOWN())) {
850
//						String featureLabel = textData.getFeature().getLabel(lang);
851
//
852
//						if(doItBetter){
853
//							/*
854
//							 *  WARNING
855
//							 *  The code lines below are desinged to handle
856
//							 *  a special case where as the feature label contains
857
//							 *  hierarchical information on the features. This code
858
//							 *  exist only as a base for discussion, and is not
859
//							 *  intendet to be used in production.
860
//							 */
861
//							featureLabel = StringUtils.remove(featureLabel, '>');
862
//
863
//							String[] labelTokens = StringUtils.split(featureLabel, '<');
864
//							if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
865
//								if(naturalLanguageDescription.length() > 0){
866
//									naturalLanguageDescription.append(separator);
867
//								}
868
//								naturalLanguageDescription.append(labelTokens[1]);
869
//							} else {
870
//								if(naturalLanguageDescription.length() > 0){
871
//									naturalLanguageDescription.append(categorySeparator);
872
//								}
873
//								naturalLanguageDescription.append(StringUtils.join(labelTokens));
874
//							}
875
//							lastCategory = labelTokens[0];
876
//							// end of demo code
877
//						} else {
878
//							if(naturalLanguageDescription.length() > 0){
879
//								naturalLanguageDescription.append(separator);
880
//							}
881
//							naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
882
//						}
883
//					} else {
884
//						if(naturalLanguageDescription.length() > 0){
885
//							naturalLanguageDescription.append(separator);
886
//						}
887
//					}
888
//					String text = textData.getMultilanguageText().values().iterator().next().getText();
889
//					naturalLanguageDescription.append(text);
890
//
891
//				}
892
//			}
893

    
894
        }
895
        else if (isUseDescription) {
896
            //AT: Left Blank in case we need to generate a Natural language text string.
897
        }
898
        return naturalLanguageDescription.toString();
899
    }
900

    
901

    
902
    @Override
903
    public boolean hasStructuredData(DescriptionBase<?> description) {
904
        return load(description.getUuid()).hasStructuredData();
905
    }
906

    
907

    
908
    @Override
909
   // @Transactional(readOnly = false)
910
    public UpdateResult moveDescriptionElementsToDescription(
911
            Collection<DescriptionElementBase> descriptionElements,
912
            DescriptionBase targetDescription,
913
            boolean isCopy,
914
            boolean setNameInSource) {
915

    
916
        UpdateResult result = new UpdateResult();
917
        if (descriptionElements.isEmpty() || descriptionElements.iterator().next() == null){
918
            result.setAbort();
919
            return result;
920
        }
921

    
922

    
923
        if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
924
            //if the descriptionElements collection is the elements set of a description, put it in a separate set before to avoid concurrent modification exceptions
925
            descriptionElements = new HashSet<DescriptionElementBase>(descriptionElements);
926
//			descriptionElementsTmp.addAll(descriptionElements);
927
//			descriptionElements = descriptionElementsTmp;
928
        }
929
        for (DescriptionElementBase element : descriptionElements){
930
            DescriptionBase<?> description = element.getInDescription();
931
            description = HibernateProxyHelper.deproxy(dao.load(description.getUuid()));
932
            Taxon taxon;
933
            TaxonName name = null;
934
            if (description instanceof TaxonDescription){
935
                TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
936
                if (taxonDescription.getTaxon() != null){
937
                    taxon = (Taxon) taxonDao.load(taxonDescription.getTaxon().getUuid());
938
                    name = taxon.getName();
939
                }
940

    
941

    
942
            }
943
            DescriptionElementBase newElement = element.clone();
944
            if (setNameInSource) {
945
                for (DescriptionElementSource source: newElement.getSources()){
946
                        if (source.getNameUsedInSource() == null){
947
                            source.setNameUsedInSource(name);
948
                        }
949
                    }
950

    
951
            }
952
            targetDescription.addElement(newElement);
953
            if (! isCopy){
954
                description.removeElement(element);
955
                dao.saveOrUpdate(description);
956
                result.addUpdatedObject(description);
957
//                if (description.getElements().isEmpty()){
958
//                   if (description instanceof TaxonDescription){
959
//                       TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
960
//                       if (taxDescription.getTaxon() != null){
961
//                           taxDescription.getTaxon().removeDescription((TaxonDescription)description);
962
//                       }
963
//                   }
964
//                    dao.delete(description);
965
//
966
//                }//else{
967
//                    dao.saveOrUpdate(description);
968
//                    result.addUpdatedObject(description);
969
//                }
970
            }
971

    
972

    
973
        }
974
        dao.saveOrUpdate(targetDescription);
975
        result.addUpdatedObject(targetDescription);
976
        if (targetDescription instanceof TaxonDescription){
977
            result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
978
        }
979
        return result;
980
    }
981

    
982
    @Override
983
    @Transactional(readOnly = false)
984
    public UpdateResult moveDescriptionElementsToDescription(
985
            Set<UUID> descriptionElementUUIDs,
986
            UUID targetDescriptionUuid,
987
            boolean isCopy, boolean setNameInSource) {
988
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
989
        for(UUID deUuid : descriptionElementUUIDs) {
990
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
991
            if (element != null){
992
                descriptionElements.add(element);
993
            }
994
        }
995
        DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
996

    
997
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
998
    }
999

    
1000
    @Override
1001
    @Transactional(readOnly = false)
1002
    public UpdateResult moveDescriptionElementsToDescription(
1003
            Set<UUID> descriptionElementUUIDs,
1004
            DescriptionBase targetDescription,
1005
            boolean isCopy, boolean setNameInSource) {
1006
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
1007
        for(UUID deUuid : descriptionElementUUIDs) {
1008
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
1009
            if (element != null){
1010
                descriptionElements.add(element);
1011
            }
1012
        }
1013
        DescriptionBase newTargetDescription;
1014
        if (targetDescription.isPersited()){
1015
            newTargetDescription = dao.load(targetDescription.getUuid());
1016
        }else{
1017
            if (targetDescription instanceof TaxonDescription){
1018
                Taxon taxon = (Taxon)taxonDao.load(((TaxonDescription)targetDescription).getTaxon().getUuid());
1019

    
1020
                newTargetDescription = TaxonDescription.NewInstance(taxon, targetDescription.isImageGallery());
1021

    
1022
            }else if (targetDescription instanceof TaxonNameDescription){
1023
                TaxonName name = nameDao.load(((TaxonNameDescription)targetDescription).getTaxonName().getUuid());
1024
                newTargetDescription = TaxonNameDescription.NewInstance(name);
1025
            }else {
1026
                SpecimenOrObservationBase specimen = occurrenceDao.load(((SpecimenDescription)targetDescription).getDescribedSpecimenOrObservation().getUuid());
1027
                newTargetDescription = SpecimenDescription.NewInstance(specimen);
1028
            }
1029

    
1030
            newTargetDescription.addSources(targetDescription.getSources());
1031
            newTargetDescription.setTitleCache(targetDescription.getTitleCache(), targetDescription.isProtectedTitleCache());
1032

    
1033
        }
1034
        return moveDescriptionElementsToDescription(descriptionElements, newTargetDescription, isCopy, setNameInSource);
1035
    }
1036

    
1037

    
1038
    @Override
1039
    @Transactional(readOnly = false)
1040
    public UpdateResult moveDescriptionElementsToDescription(
1041
            Set<UUID> descriptionElementUUIDs,
1042
            UUID targetTaxonUuid,
1043
            String moveMessage,
1044
            boolean isCopy, boolean setNameInSource) {
1045
        Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
1046
        DescriptionBase targetDescription = TaxonDescription.NewInstance(targetTaxon);
1047
        targetDescription.setTitleCache(moveMessage, true);
1048
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
1049
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
1050
        targetDescription.addAnnotation(annotation);
1051

    
1052
        targetDescription = dao.save(targetDescription);
1053
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
1054
        for(UUID deUuid : descriptionElementUUIDs) {
1055
            descriptionElements.add(descriptionElementDao.load(deUuid));
1056
        }
1057

    
1058
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
1059
    }
1060

    
1061
    @Override
1062
    public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
1063
            Integer pageIndex){
1064
        List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
1065
        List<TermDto> subList = PagerUtils.pageList(results, pageIndex, pageSize);
1066
        return new DefaultPagerImpl<TermDto>(pageIndex, results.size(), pageSize, subList);
1067
    }
1068

    
1069

    
1070
    @Override
1071
    @Transactional(readOnly = false)
1072
    public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon, boolean setNameInSource) {
1073
        List<TaxonDescription> descriptions = new ArrayList<>(sourceTaxon.getDescriptions());
1074
        UpdateResult result = new UpdateResult();
1075
        result.addUpdatedObject(sourceTaxon);
1076
        result.addUpdatedObject(targetTaxon);
1077
        for(TaxonDescription description : descriptions){
1078
            targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
1079
        }
1080
        return result;
1081
    }
1082

    
1083
    private TaxonDescription prepareDescriptionForMove(TaxonDescription description, Taxon sourceTaxon, boolean setNameInSource){
1084
        String moveMessage = String.format("Description moved from %s", sourceTaxon);
1085
        if(description.isProtectedTitleCache()){
1086
            String separator = "";
1087
            if(!StringUtils.isBlank(description.getTitleCache())){
1088
                separator = " - ";
1089
            }
1090
            description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
1091
        }
1092
        else{
1093
            description.setTitleCache(moveMessage, true);
1094
        }
1095
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
1096
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
1097
        description.addAnnotation(annotation);
1098
        if(setNameInSource){
1099
            for (DescriptionElementBase element: description.getElements()){
1100
                for (DescriptionElementSource source: element.getSources()){
1101
                    if (source.getNameUsedInSource() == null){
1102
                        source.setNameUsedInSource(sourceTaxon.getName());
1103
                    }
1104
                }
1105
            }
1106
        }
1107
        return description;
1108
    }
1109

    
1110
    @Override
1111
    @Transactional(readOnly = false)
1112
    public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid, boolean setNameInSource) {
1113
        Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
1114
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
1115
        return moveTaxonDescriptions(sourceTaxon, targetTaxon, setNameInSource);
1116

    
1117
    }
1118

    
1119
    @Override
1120
    @Transactional(readOnly = false)
1121
    public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid, boolean setNameInSource){
1122
        TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
1123
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
1124
        Taxon sourceTaxon = description.getTaxon();
1125
        UpdateResult result = new UpdateResult();
1126
        result.addUpdatedObject(sourceTaxon);
1127
        result.addUpdatedObject(targetTaxon);
1128

    
1129
        targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
1130
        return result;
1131

    
1132
    }
1133

    
1134
    @Override
1135
    public DescriptionBaseDto loadDto(UUID descriptionUuid) {
1136
        String sqlSelect =  DescriptionBaseDto.getDescriptionBaseDtoSelect();
1137
        Query query =  getSession().createQuery(sqlSelect);
1138
        query.setParameter("uuid", descriptionUuid);
1139

    
1140
        @SuppressWarnings("unchecked")
1141
        List<Object[]> result = query.list();
1142

    
1143
        List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1144

    
1145
        if (list.size()== 1){
1146
            return list.get(0);
1147
        }else{
1148
            return null;
1149
        }
1150

    
1151
    }
1152

    
1153
    @Override
1154
    public List<DescriptionBaseDto> loadDtosForTaxon(UUID taxonUuid) {
1155
        String sqlSelect =  DescriptionBaseDto.getDescriptionBaseDtoForTaxonSelect(taxonUuid);
1156
        Query query =  getSession().createQuery(sqlSelect);
1157

    
1158
        @SuppressWarnings("unchecked")
1159
        List<Object[]> result = query.list();
1160

    
1161
        List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1162

    
1163
        return list;
1164

    
1165
    }
1166

    
1167

    
1168
}
(11-11/97)