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
            if (descSpecimen != null ){
490

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

    
497
                DescriptionBase<?> desc = null;
498
                for (DescriptionBase<?> tempDesc: descSpecimen){
499
                    if (tempDesc.getUuid().equals(descDto.getDescriptionUuid())){
500
                        desc = tempDesc;
501
                        break;
502
                    }
503
                }
504

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

    
522
//                description.setDescribedSpecimenOrObservation(null);
523

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

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

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

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

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

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

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

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

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

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

    
621
                        }
622
                    }
623
                  //remove deleted elements
624

    
625
                }
626

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

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

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

    
648
        }
649

    
650
        return result;
651
    }
652

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

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

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

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

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

    
686

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

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

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

    
719
        return deleteResult;
720
    }
721

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

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

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

    
756
        return result;
757
    }
758

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

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

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

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

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

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

    
803
        StringBuilder naturalLanguageDescription = new StringBuilder();
804

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

    
814
            }
815
        }
816

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

    
819

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

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

    
826
            boolean useMicroFormatQuantitativeDescriptionBuilder = false;
827

    
828
            if(useMicroFormatQuantitativeDescriptionBuilder){
829

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

    
834
            } else {
835

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

    
842
            return naturalLanguageDescriptionText.getText(lang);
843

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

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

    
902

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

    
908

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

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

    
923

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

    
942

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

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

    
973

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

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

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

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

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

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

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

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

    
1038

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

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

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

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

    
1070

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

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

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

    
1118
    }
1119

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

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

    
1133
    }
1134

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

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

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

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

    
1152
    }
1153

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

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

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

    
1164
        return list;
1165

    
1166
    }
1167

    
1168

    
1169
}
(11-11/97)