Project

General

Profile

Download (57.1 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.api.service;
10

    
11
import java.util.ArrayList;
12
import java.util.Arrays;
13
import java.util.Collection;
14
import java.util.HashMap;
15
import java.util.HashSet;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Set;
20
import java.util.UUID;
21
import java.util.stream.Collectors;
22

    
23
import org.apache.commons.lang.StringUtils;
24
import org.apache.log4j.Logger;
25
import org.hibernate.Query;
26
import org.springframework.beans.factory.annotation.Autowired;
27
import org.springframework.stereotype.Service;
28
import org.springframework.transaction.annotation.Transactional;
29

    
30
import eu.etaxonomy.cdm.api.service.description.MissingMaximumMode;
31
import eu.etaxonomy.cdm.api.service.description.MissingMinimumMode;
32
import eu.etaxonomy.cdm.api.service.description.StructuredDescriptionAggregation;
33
import eu.etaxonomy.cdm.api.service.dto.CategoricalDataDto;
34
import eu.etaxonomy.cdm.api.service.dto.DescriptionBaseDto;
35
import eu.etaxonomy.cdm.api.service.dto.DescriptionElementDto;
36
import eu.etaxonomy.cdm.api.service.dto.QuantitativeDataDto;
37
import eu.etaxonomy.cdm.api.service.dto.StateDataDto;
38
import eu.etaxonomy.cdm.api.service.dto.StatisticalMeasurementValueDto;
39
import eu.etaxonomy.cdm.api.service.dto.TaxonDistributionDTO;
40
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
41
import eu.etaxonomy.cdm.api.service.pager.Pager;
42
import eu.etaxonomy.cdm.api.service.pager.PagerUtils;
43
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
44
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
45
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
46
import eu.etaxonomy.cdm.format.description.MicroFormatQuantitativeDescriptionBuilder;
47
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
48
import eu.etaxonomy.cdm.model.common.Annotation;
49
import eu.etaxonomy.cdm.model.common.AnnotationType;
50
import eu.etaxonomy.cdm.model.common.CdmBase;
51
import eu.etaxonomy.cdm.model.common.Language;
52
import eu.etaxonomy.cdm.model.common.Marker;
53
import eu.etaxonomy.cdm.model.common.MarkerType;
54
import eu.etaxonomy.cdm.model.description.CategoricalData;
55
import eu.etaxonomy.cdm.model.description.DescriptionBase;
56
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
57
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
58
import eu.etaxonomy.cdm.model.description.DescriptionType;
59
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
60
import eu.etaxonomy.cdm.model.description.Feature;
61
import eu.etaxonomy.cdm.model.description.MeasurementUnit;
62
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
63
import eu.etaxonomy.cdm.model.description.QuantitativeData;
64
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
65
import eu.etaxonomy.cdm.model.description.State;
66
import eu.etaxonomy.cdm.model.description.StateData;
67
import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
68
import eu.etaxonomy.cdm.model.description.StatisticalMeasurementValue;
69
import eu.etaxonomy.cdm.model.description.TaxonDescription;
70
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
71
import eu.etaxonomy.cdm.model.description.TextData;
72
import eu.etaxonomy.cdm.model.location.NamedArea;
73
import eu.etaxonomy.cdm.model.media.Media;
74
import eu.etaxonomy.cdm.model.name.TaxonName;
75
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
76
import eu.etaxonomy.cdm.model.reference.CdmLinkSource;
77
import eu.etaxonomy.cdm.model.reference.ICdmTarget;
78
import eu.etaxonomy.cdm.model.taxon.Taxon;
79
import eu.etaxonomy.cdm.model.term.DefinedTerm;
80
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
81
import eu.etaxonomy.cdm.model.term.TermTree;
82
import eu.etaxonomy.cdm.model.term.TermVocabulary;
83
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
84
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionElementDao;
85
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
86
import eu.etaxonomy.cdm.persistence.dao.description.IStatisticalMeasurementValueDao;
87
import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
88
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
89
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
90
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
91
import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
92
import eu.etaxonomy.cdm.persistence.dao.term.ITermNodeDao;
93
import eu.etaxonomy.cdm.persistence.dao.term.ITermTreeDao;
94
import eu.etaxonomy.cdm.persistence.dao.term.ITermVocabularyDao;
95
import eu.etaxonomy.cdm.persistence.dto.FeatureDto;
96
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
97
import eu.etaxonomy.cdm.persistence.dto.SortableTaxonNodeQueryResult;
98
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
99
import eu.etaxonomy.cdm.persistence.dto.TermDto;
100
import eu.etaxonomy.cdm.persistence.query.OrderHint;
101
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
102

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

    
115
    private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
116

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

    
131
    //TODO change to Interface
132
    private NaturalLanguageGenerator naturalLanguageGenerator;
133

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

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

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

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

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

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

    
164

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
259
        return listDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
260
    }
261

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

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

    
271
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
272
    }
273

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

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

    
288
    @Override
289
    public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Set<MarkerType> markerTypes, Set<DescriptionType> descriptionTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
290
        long numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes);
291

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

    
297
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
298
    }
299

    
300
    @Override
301
    public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Set<MarkerType> markerTypes, Set<DescriptionType> descriptionTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
302
        List<TaxonDescription> results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
303
        return results;
304
    }
305

    
306

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

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

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

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

    
326
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
327
    }
328

    
329

    
330
    @Override
331
    public Pager<DescriptionBase> page(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText, Set<Feature> feature, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
332
        long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
333

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

    
340
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
341
    }
342

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

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

    
356
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
357
    }
358

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

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

    
373
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
374
    }
375

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

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

    
393
        return mergedObjects;
394
    }
395

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

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

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

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

    
446
            Set<DescriptionBase> descSpecimen = descriptionSpecimenMap.get(describedObjectUuid);
447

    
448
            if (descSpecimen != null ){
449

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

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

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

    
481
//                description.setDescribedSpecimenOrObservation(null);
482

    
483
                for (DescriptionElementDto descElement: elements){
484
                    if (descElement == null){
485
                        continue;
486
                    }
487
                    UUID descElementUuid = descElement.getElementUuid();
488
                    if (descElement instanceof CategoricalDataDto && ((CategoricalDataDto)descElement).getStates().isEmpty() || descElement instanceof QuantitativeDataDto && ((QuantitativeDataDto)descElement).getValues().isEmpty()){
489
                        continue;
490
                    }
491
                    List<DescriptionElementBase> equalUuidsElements = descriptionElements.stream().filter( e -> e.getUuid().equals(descElementUuid)).collect(Collectors.toList());
492
                    eu.etaxonomy.cdm.model.description.Feature feature =  DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Feature.class, descElement.getFeatureUuid());
493
                    if (feature == null){
494
                        feature = DefinedTermBase.getTermByClassAndUUID(eu.etaxonomy.cdm.model.description.Character.class, descElement.getFeatureUuid());
495
                    }
496
                    if (equalUuidsElements.size() == 0){
497
                        if (descElement instanceof CategoricalDataDto){
498

    
499
                            CategoricalData elementBase = CategoricalData.NewInstance(feature);
500
                            List<StateDataDto> stateDtos = ((CategoricalDataDto)descElement).getStates();
501
                            for (StateDataDto dataDto: stateDtos){
502
                                //create new statedata
503
                                State newState = DefinedTermBase.getTermByClassAndUUID(State.class, dataDto.getState().getUuid());
504
                                StateData newStateData = StateData.NewInstance(newState);
505
                                elementBase.addStateData(newStateData);
506
                            }
507
                            desc.addElement(elementBase);
508
                        }
509
                        if (descElement instanceof QuantitativeDataDto){
510

    
511
                            QuantitativeData data = QuantitativeData.NewInstance(feature);
512
                            if (((QuantitativeDataDto) descElement).getMeasurementUnit() != null){
513
                                MeasurementUnit unit = DefinedTermBase.getTermByClassAndUUID(MeasurementUnit.class, ((QuantitativeDataDto) descElement).getMeasurementUnit().getUuid());
514
                                data.setUnit(unit);
515
                            }
516
                            Set<StatisticalMeasurementValue> statisticalValues = new HashSet<>();
517
                            Set<StatisticalMeasurementValueDto> valueDtos = ((QuantitativeDataDto)descElement).getValues();
518
                            data.getStatisticalValues().clear();
519
                            for (StatisticalMeasurementValueDto dataDto: valueDtos){
520
                                //create new statedata
521
                                StatisticalMeasurementValue newStatisticalMeasurement = StatisticalMeasurementValue.NewInstance(DefinedTermBase.getTermByClassAndUUID(StatisticalMeasure.class, dataDto.getType().getUuid()), dataDto.getValue());
522
                                statisticalValues.add(newStatisticalMeasurement);
523
                                data.addStatisticalValue(newStatisticalMeasurement);
524
                            }
525

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

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

    
540
                            data.getStateData().clear();
541
                            if (stateDtos.isEmpty()){
542
                                desc.removeElement(data);
543
                            }else{
544
                                for (StateDataDto dataDto: stateDtos){
545
                                        State newState = DefinedTermBase.getTermByClassAndUUID(State.class, dataDto.getState().getUuid());
546
                                        StateData newStateData = StateData.NewInstance(newState);
547
                                        data.addStateData(newStateData);
548
                                }
549
                            }
550

    
551
                        }else if (elementBase.isInstanceOf(QuantitativeData.class)){
552
                            QuantitativeData data = HibernateProxyHelper.deproxy(elementBase, QuantitativeData.class);
553

    
554
                            Set<StatisticalMeasurementValue> statisticalValues = new HashSet<>();
555
                            if (((QuantitativeDataDto) descElement).getMeasurementUnit() != null){
556
                                MeasurementUnit unit = DefinedTermBase.getTermByClassAndUUID(MeasurementUnit.class, ((QuantitativeDataDto) descElement).getMeasurementUnit().getUuid());
557
                                if (data.getUnit() == null || (data.getUnit() != null && !data.getUnit().equals(unit))){
558
                                    data.setUnit(unit);
559
                                }
560
                            }
561
                            Set<StatisticalMeasurementValueDto> valueDtos = ((QuantitativeDataDto)descElement).getValues();
562
                            data.getStatisticalValues().clear();
563
                            if (valueDtos.isEmpty()){
564
                                desc.removeElement(data);
565
                            }else{
566
                                for (StatisticalMeasurementValueDto dataDto: valueDtos){
567
                                    //create new statedata
568
                                    StatisticalMeasure statMeasure = DefinedTermBase.getTermByClassAndUUID(StatisticalMeasure.class, dataDto.getType().getUuid());
569

    
570
                                    StatisticalMeasurementValue newStatisticalMeasurement = StatisticalMeasurementValue.NewInstance(statMeasure, dataDto.getValue());
571
                                    statisticalValues.add(newStatisticalMeasurement);
572
                                    data.addStatisticalValue(newStatisticalMeasurement);
573
                                }
574

    
575
    //                            data.getStatisticalValues().addAll(statisticalValues);
576
                                data = StructuredDescriptionAggregation.handleMissingMinOrMax(data,
577
                                        MissingMinimumMode.MinToZero, MissingMaximumMode.MaxToMin);
578
                            }
579

    
580
                        }
581
                    }
582
                  //remove deleted elements
583

    
584
                }
585

    
586
                descriptionSpecimenMap.get(describedObjectUuid).add(desc);
587

    
588
                description = desc;
589
            }
590
            try{
591
                if (description != null){
592
                    mergeResult = dao.merge(description, true);
593
                    result.addUpdatedObject( mergeResult.getMergedEntity());
594
                }
595

    
596
//                if (description instanceof SpecimenDescription){
597
//                    result.addUpdatedObject(mergeResult.getMergedEntity().getDescribedSpecimenOrObservation());
598
//                }else if (description instanceof TaxonDescription){
599
//                    result.addUpdatedObject(((TaxonDescription)mergeResult.getMergedEntity()).getTaxon());
600
//                }else if (description instanceof TaxonNameDescription){
601
//                    result.addUpdatedObject(((TaxonNameDescription)mergeResult.getMergedEntity()).getTaxonName());
602
//                }
603
            }catch(Exception e){
604
                e.printStackTrace();
605
            }
606

    
607
        }
608

    
609
        return result;
610
    }
611

    
612
    @Override
613
    @Transactional(readOnly = false)
614
    public DeleteResult deleteDescription(DescriptionBase<?> description) {
615

    
616
        DeleteResult deleteResult = new DeleteResult();
617
        if (description == null){
618
            return deleteResult;
619
        }
620
        //avoid lazy init exception
621
        description = load(description.getId(), Arrays.asList("descriptiveDataSets"));
622

    
623
        deleteResult = isDeletable(description.getUuid());
624
        if (deleteResult.getRelatedObjects() != null && deleteResult.getRelatedObjects().size() == 1){
625
            Iterator<CdmBase> relObjects = deleteResult.getRelatedObjects().iterator();
626
            CdmBase next = relObjects.next();
627
            if (next instanceof CdmLinkSource){
628
                CdmLinkSource source = (CdmLinkSource)next;
629
                ICdmTarget target = source.getTarget();
630

    
631

    
632
            }
633
        }
634
        if (deleteResult.isOk() ){
635
            CdmBase.deproxy(description);
636
        	if (description instanceof TaxonDescription){
637
        		TaxonDescription taxDescription = (TaxonDescription)description;
638
        		Taxon tax = taxDescription.getTaxon();
639
        		if (tax != null){
640
        		    tax.removeDescription(taxDescription, true);
641
        		    deleteResult.addUpdatedObject(tax);
642
        		}
643
        	}
644
        	else if (description instanceof SpecimenDescription){
645
        	    SpecimenDescription specimenDescription = (SpecimenDescription)description;
646
        	    SpecimenOrObservationBase<?> specimen = specimenDescription.getDescribedSpecimenOrObservation();
647
        	    if (specimen != null){
648
        	        specimen.removeDescription(specimenDescription);
649
        	        deleteResult.addUpdatedObject(specimen);
650
        	    }
651
        	}
652

    
653
        	for (DescriptiveDataSet dataset : description.getDescriptiveDataSets()) {
654
        	    dataset.removeDescription(description);
655
            }
656

    
657
        	dao.delete(description);
658
        	deleteResult.addDeletedObject(description);
659
        	deleteResult.setCdmEntity(description);
660
        }else{
661
            logger.info(deleteResult.getExceptions().toString());
662
        }
663

    
664
        return deleteResult;
665
    }
666

    
667
    @Override
668
    @Transactional(readOnly = false)
669
    public DeleteResult deleteDescription(UUID descriptionUuid) {
670
        return deleteDescription(dao.load(descriptionUuid));
671
    }
672

    
673

    
674

    
675
    @Override
676
    public DeleteResult isDeletable(UUID descriptionUuid){
677
        DeleteResult result = new DeleteResult();
678
        DescriptionBase<?> description = this.load(descriptionUuid);
679
        Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(description);
680

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

    
703
        return result;
704
    }
705

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

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

    
723
    @Override
724
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElementsForTaxon(
725
            Taxon taxon, Set<Feature> features,
726
            Class<T> type, Integer pageSize,
727
            Integer pageNumber, List<String> propertyPaths) {
728
        if (logger.isDebugEnabled()){logger.debug(" get count ...");}
729
        Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type);
730
        List<T> descriptionElements;
731
        if(AbstractPagerImpl.hasResultsInRange(count, pageNumber, pageSize)){ // no point checking again
732
            if (logger.isDebugEnabled()){logger.debug(" get list ...");}
733
            descriptionElements = listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
734
        } else {
735
            descriptionElements = new ArrayList<T>(0);
736
        }
737
        if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
738
        return new DefaultPagerImpl<T>(pageNumber, count, pageSize, descriptionElements);
739
    }
740

    
741
    @Override
742
    public String generateNaturalLanguageDescription(TermTree featureTree,
743
            TaxonDescription description, List<Language> preferredLanguages, String separator) {
744

    
745
        Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
746

    
747
        description = (TaxonDescription)load(description.getUuid());
748
        featureTree = featureTreeDao.load(featureTree.getUuid());
749

    
750
        StringBuilder naturalLanguageDescription = new StringBuilder();
751

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

    
761
            }
762
        }
763

    
764
        if(description.hasStructuredData() && !isUseDescription){
765

    
766

    
767
            String lastCategory = null;
768
            String categorySeparator = ". ";
769

    
770
            List<TextData> textDataList;
771
            TextData naturalLanguageDescriptionText = null;
772

    
773
            boolean useMicroFormatQuantitativeDescriptionBuilder = false;
774

    
775
            if(useMicroFormatQuantitativeDescriptionBuilder){
776

    
777
                MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
778
                naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
779
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
780

    
781
            } else {
782

    
783
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
784
                        featureTree,
785
                        (description),
786
                        lang);
787
            }
788

    
789
            return naturalLanguageDescriptionText.getText(lang);
790

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

    
842
        }
843
        else if (isUseDescription) {
844
            //AT: Left Blank in case we need to generate a Natural language text string.
845
        }
846
        return naturalLanguageDescription.toString();
847
    }
848

    
849

    
850
    @Override
851
    public boolean hasStructuredData(DescriptionBase<?> description) {
852
        return load(description.getUuid()).hasStructuredData();
853
    }
854

    
855

    
856
    @Override
857
   // @Transactional(readOnly = false)
858
    public UpdateResult moveDescriptionElementsToDescription(
859
            Collection<DescriptionElementBase> descriptionElements,
860
            DescriptionBase targetDescription,
861
            boolean isCopy,
862
            boolean setNameInSource) {
863

    
864
        UpdateResult result = new UpdateResult();
865
        if (descriptionElements.isEmpty() || descriptionElements.iterator().next() == null){
866
            result.setAbort();
867
            return result;
868
        }
869

    
870

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

    
889

    
890
            }
891
            DescriptionElementBase newElement = element.clone();
892
            if (setNameInSource) {
893
                for (DescriptionElementSource source: newElement.getSources()){
894
                        if (source.getNameUsedInSource() == null){
895
                            source.setNameUsedInSource(name);
896
                        }
897
                    }
898

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

    
920

    
921
        }
922
        dao.saveOrUpdate(targetDescription);
923
        result.addUpdatedObject(targetDescription);
924
        if (targetDescription instanceof TaxonDescription){
925
            result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
926
        }
927
        return result;
928
    }
929

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

    
945
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
946
    }
947

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

    
968
                newTargetDescription = TaxonDescription.NewInstance(taxon, targetDescription.isImageGallery());
969

    
970
            }else if (targetDescription instanceof TaxonNameDescription){
971
                TaxonName name = nameDao.load(((TaxonNameDescription)targetDescription).getTaxonName().getUuid());
972
                newTargetDescription = TaxonNameDescription.NewInstance(name);
973
            }else {
974
                SpecimenOrObservationBase specimen = occurrenceDao.load(((SpecimenDescription)targetDescription).getDescribedSpecimenOrObservation().getUuid());
975
                newTargetDescription = SpecimenDescription.NewInstance(specimen);
976
            }
977

    
978
            newTargetDescription.addSources(targetDescription.getSources());
979
            newTargetDescription.setTitleCache(targetDescription.getTitleCache(), targetDescription.isProtectedTitleCache());
980

    
981
        }
982
        return moveDescriptionElementsToDescription(descriptionElements, newTargetDescription, isCopy, setNameInSource);
983
    }
984

    
985

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

    
1000
        targetDescription = dao.save(targetDescription);
1001
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
1002
        for(UUID deUuid : descriptionElementUUIDs) {
1003
            descriptionElements.add(descriptionElementDao.load(deUuid));
1004
        }
1005

    
1006
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
1007
    }
1008

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

    
1017

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

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

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

    
1065
    }
1066

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

    
1077
        targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
1078
        return result;
1079

    
1080
    }
1081

    
1082
    @Override
1083
    public DescriptionBaseDto loadDto(UUID descriptionUuid) {
1084
        String sqlSelect =  DescriptionBaseDto.getDescriptionBaseDtoSelect();
1085
        Query query =  getSession().createQuery(sqlSelect);
1086
        List<UUID> uuids = new ArrayList<UUID>();
1087
        uuids.add(descriptionUuid);
1088
        query.setParameterList("uuid", uuids);
1089

    
1090
        @SuppressWarnings("unchecked")
1091
        List<Object[]> result = query.list();
1092

    
1093
        List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1094

    
1095
        if (list.size()== 1){
1096
            DescriptionBaseDto dto = list.get(0);
1097
            //get categorical data
1098
            sqlSelect = CategoricalDataDto.getCategoricalDtoSelect();
1099
            query =  getSession().createQuery(sqlSelect);
1100
            query.setParameter("uuid", descriptionUuid);
1101
            @SuppressWarnings("unchecked")
1102
            List<Object[]>  resultCat = query.list();
1103
            List<CategoricalDataDto> listCategorical = CategoricalDataDto.categoricalDataDtoListFrom(resultCat);
1104

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

    
1128
    }
1129
    @Override
1130
    public List<DescriptionBaseDto> loadDtos(Set<UUID> descriptionUuids) {
1131
        String sqlSelect =  DescriptionBaseDto.getDescriptionBaseDtoSelect();
1132
        Query query =  getSession().createQuery(sqlSelect);
1133
        query.setParameterList("uuid", descriptionUuids);
1134

    
1135
        @SuppressWarnings("unchecked")
1136
        List<Object[]> result = query.list();
1137

    
1138
        List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1139

    
1140
        for (DescriptionBaseDto dto: list){
1141

    
1142
            //get categorical data
1143
            sqlSelect = CategoricalDataDto.getCategoricalDtoSelect();
1144
            query =  getSession().createQuery(sqlSelect);
1145
            query.setParameter("uuid", dto.getDescriptionUuid());
1146
            @SuppressWarnings("unchecked")
1147
            List<Object[]>  resultCat = query.list();
1148
            List<CategoricalDataDto> listCategorical = CategoricalDataDto.categoricalDataDtoListFrom(resultCat);
1149

    
1150
            List<UUID> featureUuids = new ArrayList<>();
1151
            for (CategoricalDataDto catDto: listCategorical){
1152
                featureUuids.add(catDto.getFeatureUuid());
1153
            }
1154
            Map<UUID, TermDto> featureDtos = termService.findFeatureByUUIDsAsDtos(featureUuids);
1155
            for (CategoricalDataDto catDto: listCategorical){
1156
                FeatureDto featuredto = (FeatureDto)featureDtos.get(catDto.getFeatureUuid());
1157
                catDto.setFeatureDto(featuredto);
1158
            }
1159
            dto.getElements().addAll(listCategorical);
1160
            //get quantitative data
1161
            sqlSelect = QuantitativeDataDto.getQuantitativeDataDtoSelect();
1162
            query =  getSession().createQuery(sqlSelect);
1163
            query.setParameter("uuid",  dto.getDescriptionUuid());
1164
            @SuppressWarnings("unchecked")
1165
            List<Object[]>  resultQuant = query.list();
1166
            List<QuantitativeDataDto> listQuant = QuantitativeDataDto.quantitativeDataDtoListFrom(resultQuant);
1167
            dto.getElements().addAll(listQuant);
1168

    
1169
        }
1170
        return list;
1171

    
1172
    }
1173

    
1174
    @Override
1175
    public List<DescriptionBaseDto> loadDtosForTaxon(UUID taxonUuid) {
1176
        String sqlSelect =  DescriptionBaseDto.getDescriptionBaseDtoForTaxonSelect();
1177
        Query query =  getSession().createQuery(sqlSelect);
1178
        query.setParameter("uuid", taxonUuid);
1179

    
1180
        @SuppressWarnings("unchecked")
1181
        List<Object[]> result = query.list();
1182

    
1183
        List<DescriptionBaseDto> list = DescriptionBaseDto.descriptionBaseDtoListFrom(result);
1184

    
1185
        return list;
1186

    
1187
    }
1188

    
1189
    @Override
1190
    public TaxonNodeDto findTaxonNodeDtoForIndividualAssociation(UUID specimenUuid, UUID classificationUuid) {
1191
      //get specimen used in description
1192
      //get individial associations with this specimen
1193
      //get taxon node for the classification
1194
      @SuppressWarnings("unchecked")
1195
      List<SortableTaxonNodeQueryResult> result =  dao.getNodeOfIndividualAssociationForSpecimen(specimenUuid, classificationUuid);
1196

    
1197
      if (!result.isEmpty()){
1198
         List<TaxonNodeDto> dtos = taxonNodeDao.createNodeDtos(result);
1199
         if (dtos.size() == 1){
1200
             return dtos.get(0);
1201
         }else{
1202
             logger.debug("There is more than one taxon associated to the specimen with uuid: " + specimenUuid + " return the first in the list");
1203
             return dtos.get(0);
1204
         }
1205
      }
1206

    
1207

    
1208

    
1209
        return null;
1210
    }
1211

    
1212

    
1213

    
1214

    
1215
}
(12-12/95)