Project

General

Profile

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

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

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

    
569
//                            data.getStatisticalValues().addAll(statisticalValues);
570
                            data = StructuredDescriptionAggregation.handleMissingMinOrMax(data,
571
                                    MissingMinimumMode.MinToZero, MissingMaximumMode.MaxToMin);
572
                            desc.addElement(data);
573
                        }
574

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

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

    
594
                        }else if (elementBase.isInstanceOf(QuantitativeData.class)){
595
                            QuantitativeData data = HibernateProxyHelper.deproxy(elementBase, QuantitativeData.class);
596

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

    
613
                                    StatisticalMeasurementValue newStatisticalMeasurement = StatisticalMeasurementValue.NewInstance(statMeasure, dataDto.getValue());
614
                                    statisticalValues.add(newStatisticalMeasurement);
615
                                    data.addStatisticalValue(newStatisticalMeasurement);
616
                                }
617

    
618
    //                            data.getStatisticalValues().addAll(statisticalValues);
619
                                data = StructuredDescriptionAggregation.handleMissingMinOrMax(data,
620
                                        MissingMinimumMode.MinToZero, MissingMaximumMode.MaxToMin);
621
                            }
622

    
623
                        }
624
                    }
625
                  //remove deleted elements
626

    
627
                }
628

    
629
                descriptionSpecimenMap.get(describedObjectUuid).add(desc);
630

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

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

    
650
        }
651

    
652
        return result;
653
    }
654

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

    
664
    @Override
665
    public UUID deleteDescriptionElement(UUID descriptionElementUuid) {
666
        return deleteDescriptionElement(descriptionElementDao.load(descriptionElementUuid));
667
    }
668

    
669
    @Override
670
    @Transactional(readOnly = false)
671
    public DeleteResult deleteDescription(DescriptionBase<?> description) {
672

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

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

    
688

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

    
710
        	for (DescriptiveDataSet dataset : description.getDescriptiveDataSets()) {
711
        	    dataset.removeDescription(description);
712
            }
713

    
714
        	dao.delete(description);
715
        	deleteResult.addDeletedObject(description);
716
        	deleteResult.setCdmEntity(description);
717
        }else{
718
            logger.info(deleteResult.getExceptions().toString());
719
        }
720

    
721
        return deleteResult;
722
    }
723

    
724
    @Override
725
    @Transactional(readOnly = false)
726
    public DeleteResult deleteDescription(UUID descriptionUuid) {
727
        return deleteDescription(dao.load(descriptionUuid));
728
    }
729

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

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

    
758
        return result;
759
    }
760

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

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

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

    
796
    @Override
797
    public String generateNaturalLanguageDescription(TermTree featureTree,
798
            TaxonDescription description, List<Language> preferredLanguages, String separator) {
799

    
800
        Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
801

    
802
        description = (TaxonDescription)load(description.getUuid());
803
        featureTree = featureTreeDao.load(featureTree.getUuid());
804

    
805
        StringBuilder naturalLanguageDescription = new StringBuilder();
806

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

    
816
            }
817
        }
818

    
819
        if(description.hasStructuredData() && !isUseDescription){
820

    
821

    
822
            String lastCategory = null;
823
            String categorySeparator = ". ";
824

    
825
            List<TextData> textDataList;
826
            TextData naturalLanguageDescriptionText = null;
827

    
828
            boolean useMicroFormatQuantitativeDescriptionBuilder = false;
829

    
830
            if(useMicroFormatQuantitativeDescriptionBuilder){
831

    
832
                MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
833
                naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
834
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
835

    
836
            } else {
837

    
838
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
839
                        featureTree,
840
                        (description),
841
                        lang);
842
            }
843

    
844
            return naturalLanguageDescriptionText.getText(lang);
845

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

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

    
904

    
905
    @Override
906
    public boolean hasStructuredData(DescriptionBase<?> description) {
907
        return load(description.getUuid()).hasStructuredData();
908
    }
909

    
910

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

    
919
        UpdateResult result = new UpdateResult();
920
        if (descriptionElements.isEmpty() || descriptionElements.iterator().next() == null){
921
            result.setAbort();
922
            return result;
923
        }
924

    
925

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

    
944

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

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

    
975

    
976
        }
977
        dao.saveOrUpdate(targetDescription);
978
        result.addUpdatedObject(targetDescription);
979
        if (targetDescription instanceof TaxonDescription){
980
            result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
981
        }
982
        return result;
983
    }
984

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

    
1000
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
1001
    }
1002

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

    
1023
                newTargetDescription = TaxonDescription.NewInstance(taxon, targetDescription.isImageGallery());
1024

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

    
1033
            newTargetDescription.addSources(targetDescription.getSources());
1034
            newTargetDescription.setTitleCache(targetDescription.getTitleCache(), targetDescription.isProtectedTitleCache());
1035

    
1036
        }
1037
        return moveDescriptionElementsToDescription(descriptionElements, newTargetDescription, isCopy, setNameInSource);
1038
    }
1039

    
1040

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

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

    
1061
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
1062
    }
1063

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

    
1072

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

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

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

    
1120
    }
1121

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

    
1132
        targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
1133
        return result;
1134

    
1135
    }
1136

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

    
1143
        @SuppressWarnings("unchecked")
1144
        List<Object[]> result = query.list();
1145

    
1146
        List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1147

    
1148
        if (list.size()== 1){
1149
            return list.get(0);
1150
        }else{
1151
            return null;
1152
        }
1153

    
1154
    }
1155

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

    
1161
        @SuppressWarnings("unchecked")
1162
        List<Object[]> result = query.list();
1163

    
1164
        List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1165

    
1166
        return list;
1167

    
1168
    }
1169

    
1170

    
1171
}
(11-11/97)