Project

General

Profile

Download (46.3 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

    
10
package eu.etaxonomy.cdm.api.service;
11

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

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

    
29
import eu.etaxonomy.cdm.api.service.dto.DescriptionBaseDto;
30
import eu.etaxonomy.cdm.api.service.dto.TaxonDistributionDTO;
31
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
32
import eu.etaxonomy.cdm.api.service.pager.Pager;
33
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
34
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
35
import eu.etaxonomy.cdm.api.utility.DescriptionUtility;
36
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
37
import eu.etaxonomy.cdm.format.description.MicroFormatQuantitativeDescriptionBuilder;
38
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
39
import eu.etaxonomy.cdm.model.common.Annotation;
40
import eu.etaxonomy.cdm.model.common.AnnotationType;
41
import eu.etaxonomy.cdm.model.common.CdmBase;
42
import eu.etaxonomy.cdm.model.common.Language;
43
import eu.etaxonomy.cdm.model.common.Marker;
44
import eu.etaxonomy.cdm.model.common.MarkerType;
45
import eu.etaxonomy.cdm.model.description.DescriptionBase;
46
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
47
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
48
import eu.etaxonomy.cdm.model.description.DescriptionType;
49
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
50
import eu.etaxonomy.cdm.model.description.Distribution;
51
import eu.etaxonomy.cdm.model.description.Feature;
52
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
53
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
54
import eu.etaxonomy.cdm.model.description.TaxonDescription;
55
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
56
import eu.etaxonomy.cdm.model.description.TextData;
57
import eu.etaxonomy.cdm.model.location.NamedArea;
58
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
59
import eu.etaxonomy.cdm.model.media.Media;
60
import eu.etaxonomy.cdm.model.name.TaxonName;
61
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
62
import eu.etaxonomy.cdm.model.reference.CdmLinkSource;
63
import eu.etaxonomy.cdm.model.reference.ICdmTarget;
64
import eu.etaxonomy.cdm.model.taxon.Taxon;
65
import eu.etaxonomy.cdm.model.term.DefinedTerm;
66
import eu.etaxonomy.cdm.model.term.TermTree;
67
import eu.etaxonomy.cdm.model.term.TermVocabulary;
68
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
69
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionElementDao;
70
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
71
import eu.etaxonomy.cdm.persistence.dao.description.IStatisticalMeasurementValueDao;
72
import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
73
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
74
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
75
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
76
import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
77
import eu.etaxonomy.cdm.persistence.dao.term.ITermNodeDao;
78
import eu.etaxonomy.cdm.persistence.dao.term.ITermTreeDao;
79
import eu.etaxonomy.cdm.persistence.dao.term.ITermVocabularyDao;
80
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
81
import eu.etaxonomy.cdm.persistence.dto.TermDto;
82
import eu.etaxonomy.cdm.persistence.query.OrderHint;
83
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
84

    
85
/**
86
 * @author a.mueller
87
 * @author a.kohlbecker
88
 *
89
 * @since 24.06.2008
90
 *
91
 */
92
@Service
93
@Transactional(readOnly = true)
94
public class DescriptionServiceImpl
95
        extends IdentifiableServiceBase<DescriptionBase,IDescriptionDao>
96
        implements IDescriptionService {
97

    
98
    private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
99

    
100
    protected IDescriptionElementDao descriptionElementDao;
101
    protected ITermTreeDao featureTreeDao;
102
    protected IDescriptiveDataSetDao descriptiveDataSetDao;
103
    protected ITermNodeDao termNodeDao;
104
    protected ITermVocabularyDao vocabularyDao;
105
    protected IDefinedTermDao definedTermDao;
106
    protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
107
    protected ITaxonDao taxonDao;
108
    protected ITaxonNameDao nameDao;
109
    protected IOccurrenceDao occurrenceDao;
110
    protected ITaxonNodeDao taxonNodeDao;
111
    protected IDescriptiveDataSetDao dataSetDao;
112

    
113
    @Autowired
114
    private IProgressMonitorService progressMonitorService;
115

    
116
    //TODO change to Interface
117
    private NaturalLanguageGenerator naturalLanguageGenerator;
118

    
119
    @Autowired
120
    protected void setFeatureTreeDao(ITermTreeDao featureTreeDao) {
121
        this.featureTreeDao = featureTreeDao;
122
    }
123

    
124
    @Autowired
125
    protected void setDescriptiveDataSetDao(IDescriptiveDataSetDao descriptiveDataSetDao) {
126
        this.descriptiveDataSetDao = descriptiveDataSetDao;
127
    }
128

    
129
    @Autowired
130
    protected void setTermNodeDao(ITermNodeDao featureNodeDao) {
131
        this.termNodeDao = featureNodeDao;
132
    }
133

    
134
    @Autowired
135
    protected void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
136
        this.vocabularyDao = vocabularyDao;
137
    }
138

    
139
    @Autowired
140
    protected void setDefinedTermDao(IDefinedTermDao definedTermDao) {
141
        this.definedTermDao = definedTermDao;
142
    }
143

    
144
    @Autowired
145
    protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao) {
146
        this.statisticalMeasurementValueDao = statisticalMeasurementValueDao;
147
    }
148

    
149
    @Autowired
150
    protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao) {
151
        this.descriptionElementDao = descriptionElementDao;
152
    }
153

    
154
    @Autowired
155
    protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator) {
156
        this.naturalLanguageGenerator = naturalLanguageGenerator;
157
    }
158

    
159
    @Autowired
160
    protected void setTaxonDao(ITaxonDao taxonDao) {
161
        this.taxonDao = taxonDao;
162
    }
163

    
164
    @Autowired
165
    protected void setTaxonNodeDao(ITaxonNodeDao taxonNodeDao) {
166
        this.taxonNodeDao = taxonNodeDao;
167
    }
168

    
169
    @Autowired
170
    protected void setDataSetDao(IDescriptiveDataSetDao dataSetDao) {
171
        this.dataSetDao = dataSetDao;
172
    }
173

    
174
    /**
175
     *
176
     */
177
    public DescriptionServiceImpl() {
178
        logger.debug("Load DescriptionService Bean");
179
    }
180

    
181

    
182
    @Override
183
    @Transactional(readOnly = false)
184
    public UpdateResult updateCaches(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
185
        if (clazz == null){
186
            clazz = DescriptionBase.class;
187
        }
188
        return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
189
    }
190

    
191

    
192
    @Override
193
    public TermVocabulary<Feature> getDefaultFeatureVocabulary(){
194
        String uuidFeature = "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
195
        UUID featureUuid = UUID.fromString(uuidFeature);
196
        return vocabularyDao.findByUuid(featureUuid);
197
    }
198

    
199
    @Override
200
    @Autowired
201
    protected void setDao(IDescriptionDao dao) {
202
        this.dao = dao;
203
    }
204

    
205
    @Override
206
    public long count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
207
        return dao.countDescriptions(type, hasImages, hasText, feature);
208
    }
209

    
210
    @Override
211
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
212
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
213

    
214
        List<T> results = listDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
215
        return new DefaultPagerImpl<>(pageNumber, results.size(), pageSize, results);
216
    }
217

    
218
    @Override
219
    @Deprecated
220
    public <T extends DescriptionElementBase> Pager<T> getDescriptionElements(DescriptionBase description,
221
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
222
        return pageDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
223
    }
224

    
225

    
226

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

    
232
        long numberOfResults = dao.countDescriptionElements(description, descriptionType, features, type);
233
        List<T> results = new ArrayList<T>();
234
        if(AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)) {
235
            results = dao.getDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
236
        }
237
        return results;
238

    
239
    }
240

    
241

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

    
247
        return listDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
248
    }
249

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

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

    
259
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
260
    }
261

    
262

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

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

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

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

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

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

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

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

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

    
307

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

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

    
318
    @Override
319
    @Deprecated
320
    public DistributionTree getOrderedDistributions(
321
            Set<TaxonDescription> taxonDescriptions,
322
            boolean subAreaPreference,
323
            boolean statusOrderPreference,
324
            Set<MarkerType> hiddenAreaMarkerTypes,
325
            Set<NamedAreaLevel> omitLevels, List<String> propertyPaths){
326

    
327
        List<Distribution> distList = new ArrayList<Distribution>();
328

    
329
        List<UUID> uuids = new ArrayList<UUID>();
330
        for (TaxonDescription taxonDescription : taxonDescriptions) {
331
            if (! taxonDescription.isImageGallery()){    //image galleries should not have descriptions, but better filter fully on DTYPE of description element
332
                uuids.add(taxonDescription.getUuid());
333
            }
334
        }
335

    
336
        List<DescriptionBase> desclist = dao.list(uuids, null, null, null, propertyPaths);
337
        for (DescriptionBase desc : desclist) {
338
            if (desc.isInstanceOf(TaxonDescription.class)){
339
                Set<DescriptionElementBase> elements = desc.getElements();
340
                for (DescriptionElementBase element : elements) {
341
                        if (element.isInstanceOf(Distribution.class)) {
342
                            Distribution distribution = (Distribution) element;
343
                            if(distribution.getArea() != null){
344
                                distList.add(distribution);
345
                            }
346
                        }
347
                }
348
            }
349
        }
350

    
351
        //old
352
//        for (TaxonDescription taxonDescription : taxonDescriptions) {
353
//            if (logger.isDebugEnabled()){ logger.debug("load taxon description " + taxonDescription.getUuid());}
354
//        	//TODO why not loading all description via .list ? This may improve performance
355
//            taxonDescription = (TaxonDescription) dao.load(taxonDescription.getUuid(), propertyPaths);
356
//            Set<DescriptionElementBase> elements = taxonDescription.getElements();
357
//            for (DescriptionElementBase element : elements) {
358
//                    if (element.isInstanceOf(Distribution.class)) {
359
//                        Distribution distribution = (Distribution) element;
360
//                        if(distribution.getArea() != null){
361
//                            distList.add(distribution);
362
//                        }
363
//                    }
364
//            }
365
//        }
366

    
367
        if (logger.isDebugEnabled()){logger.debug("filter tree for " + distList.size() + " distributions ...");}
368

    
369
        // filter distributions
370
        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distList, hiddenAreaMarkerTypes, true, statusOrderPreference, false);
371
        distList.clear();
372
        distList.addAll(filteredDistributions);
373

    
374
        return DescriptionUtility.orderDistributions(definedTermDao, omitLevels, distList, hiddenAreaMarkerTypes, null);
375
    }
376

    
377

    
378
    @Override
379
    public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
380
        long numberOfResults = dao.countTaxonNameDescriptions(name);
381

    
382
        List<TaxonNameDescription> results = new ArrayList<>();
383
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
384
            results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
385
        }
386

    
387
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
388
    }
389

    
390

    
391
    @Override
392
    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) {
393
        long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
394

    
395
        @SuppressWarnings("rawtypes")
396
        List<DescriptionBase> results = new ArrayList<>();
397
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
398
            results = dao.listDescriptions(type, hasImages, hasText, feature, pageSize, pageNumber,orderHints,propertyPaths);
399
        }
400

    
401
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
402
    }
403

    
404
    /**
405
     * FIXME Candidate for harmonization
406
     * Rename: searchByDistribution
407
     */
408
    @Override
409
    public Pager<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm presence,	Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
410
        long numberOfResults = dao.countDescriptionByDistribution(namedAreas, presence);
411

    
412
        List<TaxonDescription> results = new ArrayList<>();
413
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
414
            results = dao.searchDescriptionByDistribution(namedAreas, presence, pageSize, pageNumber,orderHints,propertyPaths);
415
        }
416

    
417
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
418
    }
419

    
420
    /**
421
     * FIXME Candidate for harmonization
422
     * move: descriptionElementService.search
423
     */
424
    @Override
425
//    public Pager<T> searchElements(Class<? extends T> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
426
    public <S extends DescriptionElementBase> Pager<S> searchElements(Class<S> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
427
        long numberOfResults = descriptionElementDao.count(clazz, queryString);
428

    
429
        List<S> results = new ArrayList<>();
430
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
431
            results = (List<S>)descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
432
        }
433

    
434
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
435
    }
436

    
437
    /**
438
     * FIXME Candidate for harmonization
439
     * descriptionElementService.find
440
     */
441
    @Override
442
    public DescriptionElementBase getDescriptionElementByUuid(UUID uuid) {
443
        return descriptionElementDao.findByUuid(uuid);
444
    }
445

    
446
    /**
447
     * FIXME Candidate for harmonization
448
     * descriptionElementService.load
449
     */
450
    @Override
451
    public DescriptionElementBase loadDescriptionElement(UUID uuid,	List<String> propertyPaths) {
452
        return descriptionElementDao.load(uuid, propertyPaths);
453
    }
454

    
455
    /**
456
     * FIXME Candidate for harmonization
457
     * descriptionElementService.save
458
     */
459
    @Override
460
    @Transactional(readOnly = false)
461
    public UUID saveDescriptionElement(DescriptionElementBase descriptionElement) {
462
        return descriptionElementDao.save(descriptionElement).getUuid();
463
    }
464

    
465
    /**
466
     * FIXME Candidate for harmonization
467
     * descriptionElementService.save
468
     */
469
    @Override
470
    @Transactional(readOnly = false)
471
    public Map<UUID, DescriptionElementBase> saveDescriptionElement(Collection<DescriptionElementBase> descriptionElements) {
472
        return descriptionElementDao.saveAll(descriptionElements);
473
    }
474

    
475
    @Override
476
    @Transactional(readOnly = false)
477
    public List<MergeResult<DescriptionBase>> mergeDescriptionElements(Collection<TaxonDistributionDTO> descriptionElements, boolean returnTransientEntity) {
478
        List<MergeResult<DescriptionBase>> mergedObjects = new ArrayList();
479

    
480
        for(TaxonDistributionDTO obj : descriptionElements) {
481
            Iterator<TaxonDescription> iterator = obj.getDescriptionsWrapper().getDescriptions().iterator();
482
            List<DescriptionBase> list = new ArrayList(obj.getDescriptionsWrapper().getDescriptions());
483
          //  Map<UUID, DescriptionBase> map = dao.saveOrUpdateAll(list);
484
//            MergeResult<DescriptionBase> mergeResult = new MergeResult<DescriptionBase>(mergedEntity, newEntities)
485
//            mergedObjects.add(map.values());
486
            while (iterator.hasNext()){
487
                TaxonDescription desc = iterator.next();
488
                mergedObjects.add(dao.merge(desc, returnTransientEntity));
489
            }
490

    
491

    
492
        }
493

    
494
        return mergedObjects;
495
    }
496
//
497
    @Override
498
    @Transactional(readOnly = false)
499
    public UpdateResult mergeDescriptions(Collection<DescriptionBaseDto> descriptions, UUID descriptiveDataSetUuid) {
500
//        List<<DescriptionBase>> mergedObjects = new ArrayList();
501
        UpdateResult result = new UpdateResult();
502
        DescriptiveDataSet dataSet = descriptiveDataSetDao.load(descriptiveDataSetUuid);
503
        Set<DescriptionBase> descriptionsOfDataSet = dataSet.getDescriptions();
504
        HashMap<UUID, DescriptionBase> descriptionSpecimenMap = new HashMap();
505

    
506
        for (DescriptionBase descriptionBase: descriptionsOfDataSet){
507
            if (descriptionBase.getDescribedSpecimenOrObservation() != null){
508
                descriptionSpecimenMap.put(descriptionBase.getDescribedSpecimenOrObservation().getUuid(), descriptionBase);
509
            }
510
        }
511
        MergeResult<DescriptionBase> mergeResult = null;
512
        for(DescriptionBaseDto descDto : descriptions) {
513
            DescriptionBase description = descDto.getDescription();
514
            UUID describedObjectUuid = null;
515
            if (description instanceof SpecimenDescription){
516
                describedObjectUuid = descDto.getSpecimenDto().getUuid();
517
            }else if (description instanceof TaxonDescription){
518
                describedObjectUuid = descDto.getTaxonDto().getUuid();
519
            }else if (description instanceof TaxonNameDescription){
520
                describedObjectUuid = descDto.getNameDto().getUuid();
521
            }
522
            if (descriptionSpecimenMap.get(describedObjectUuid) != null && !descriptionSpecimenMap.get(describedObjectUuid).equals(description)){
523
                Set<DescriptionElementBase> elements = new HashSet();
524
                for (Object element: description.getElements()){
525
                    elements.add((DescriptionElementBase)element);
526
                }
527
                DescriptionBase desc = descriptionSpecimenMap.get(describedObjectUuid);
528
//                description.setDescribedSpecimenOrObservation(null);
529

    
530
                for (DescriptionElementBase element: elements){
531
                    desc.addElement(element);
532
                }
533
                descriptionSpecimenMap.put(describedObjectUuid, desc);
534
                description = desc;
535
            }
536
            try{
537
                mergeResult = dao.merge(description, true);
538
                result.addUpdatedObject( mergeResult.getMergedEntity());
539
//                if (description instanceof SpecimenDescription){
540
//                    result.addUpdatedObject(mergeResult.getMergedEntity().getDescribedSpecimenOrObservation());
541
//                }else if (description instanceof TaxonDescription){
542
//                    result.addUpdatedObject(((TaxonDescription)mergeResult.getMergedEntity()).getTaxon());
543
//                }else if (description instanceof TaxonNameDescription){
544
//                    result.addUpdatedObject(((TaxonNameDescription)mergeResult.getMergedEntity()).getTaxonName());
545
//                }
546
            }catch(Exception e){
547
                e.printStackTrace();
548
            }
549

    
550
        }
551

    
552
        return result;
553
    }
554

    
555
    /**
556
     * FIXME Candidate for harmonization
557
     * descriptionElementService.delete
558
     */
559
    @Override
560
    public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
561
        return descriptionElementDao.delete(descriptionElement);
562
    }
563

    
564
    @Override
565
    public UUID deleteDescriptionElement(UUID descriptionElementUuid) {
566
        return deleteDescriptionElement(descriptionElementDao.load(descriptionElementUuid));
567
    }
568

    
569
    @Override
570
    @Transactional(readOnly = false)
571
    public DeleteResult deleteDescription(DescriptionBase description) {
572

    
573
        DeleteResult deleteResult = new DeleteResult();
574
        if (description == null){
575
            return deleteResult;
576
        }
577
        description = load(description.getId(), Arrays.asList("descriptiveDataSets"));
578
        //avoid lazy init exception
579

    
580
        deleteResult = isDeletable(description.getUuid());
581
        if (deleteResult.getRelatedObjects() != null && deleteResult.getRelatedObjects().size() == 1){
582
            Iterator<CdmBase> relObjects = deleteResult.getRelatedObjects().iterator();
583
            CdmBase next = relObjects.next();
584
            if (next instanceof CdmLinkSource){
585
                CdmLinkSource source = (CdmLinkSource)next;
586
                ICdmTarget target = source.getTarget();
587

    
588

    
589
            }
590
        }
591
        if (deleteResult.isOk() ){
592
        	if (description instanceof TaxonDescription){
593
        		TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
594
        		Taxon tax = taxDescription.getTaxon();
595
        		tax.removeDescription(taxDescription, true);
596
                deleteResult.addUpdatedObject(tax);
597
        	}
598
        	else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
599
        	    SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(description, SpecimenDescription.class);
600
        	    SpecimenOrObservationBase<?> specimen = specimenDescription.getDescribedSpecimenOrObservation();
601
        	    specimen.removeDescription(specimenDescription);
602
        	    deleteResult.addUpdatedObject(specimen);
603
        	}
604

    
605
        	Set<DescriptiveDataSet> descriptiveDataSets = description.getDescriptiveDataSets();
606
        	for (Iterator<DescriptiveDataSet> iterator = descriptiveDataSets.iterator(); iterator.hasNext();) {
607
        	    iterator.next().removeDescription(description);
608
            }
609

    
610
        	dao.delete(description);
611
        	deleteResult.addDeletedObject(description);
612
        	deleteResult.setCdmEntity(description);
613
        }else{
614
            logger.info(deleteResult.getExceptions().toString());
615
        }
616

    
617
        return deleteResult;
618
    }
619

    
620
    @Override
621
    @Transactional(readOnly = false)
622
    public DeleteResult deleteDescription(UUID descriptionUuid) {
623
        return deleteDescription(dao.load(descriptionUuid));
624
    }
625

    
626
    @Override
627
    public DeleteResult isDeletable(UUID descriptionUuid){
628
        DeleteResult result = new DeleteResult();
629
        DescriptionBase<?> description = this.load(descriptionUuid);
630
        Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(description);
631

    
632
        if (references == null || references.isEmpty()){
633
            return result;
634
        }
635
        for (CdmBase ref: references){
636
            String message = null;
637
            if (description instanceof TaxonDescription && ref instanceof Taxon && ((TaxonDescription)description).getTaxon().equals(ref)){
638
                continue;
639
            } else if (description instanceof TaxonNameDescription && ref instanceof TaxonName && ((TaxonNameDescription)description).getTaxonName().equals(ref)){
640
                continue;
641
            } else if (description instanceof SpecimenDescription && ref instanceof SpecimenOrObservationBase && ((SpecimenDescription)description).getDescribedSpecimenOrObservation().equals(ref)){
642
                continue;
643
            } else if (ref instanceof DescriptionElementBase){
644
                continue;
645
            }else {
646
                message = "The description can't be completely deleted because it is referenced by " + ref.getUserFriendlyTypeName() ;
647
                result.setAbort();
648
            }
649
            if (message != null){
650
                result.addException(new ReferencedObjectUndeletableException(message));
651
                result.addRelatedObject(ref);
652
            }
653
        }
654

    
655
        return result;
656
    }
657

    
658
    @Override
659
    public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
660
        return vocabularyDao.findByUuid(uuid);
661
    }
662

    
663
    @Override
664
    @Deprecated
665
    public <T extends DescriptionElementBase> List<T> getDescriptionElementsForTaxon(
666
            Taxon taxon, Set<Feature> features,
667
            Class<T> type, Integer pageSize,
668
            Integer pageNumber, List<String> propertyPaths) {
669
        return listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
670
    }
671

    
672
    @Override
673
    public <T extends DescriptionElementBase> List<T> listDescriptionElementsForTaxon(
674
            Taxon taxon, Set<Feature> features,
675
            Class<T> type, Integer pageSize,
676
            Integer pageNumber, List<String> propertyPaths) {
677
        return dao.getDescriptionElementForTaxon(taxon.getUuid(), features, type, pageSize, pageNumber, propertyPaths);
678
    }
679

    
680
    @Override
681
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElementsForTaxon(
682
            Taxon taxon, Set<Feature> features,
683
            Class<T> type, Integer pageSize,
684
            Integer pageNumber, List<String> propertyPaths) {
685
        if (logger.isDebugEnabled()){logger.debug(" get count ...");}
686
        Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type);
687
        List<T> descriptionElements;
688
        if(AbstractPagerImpl.hasResultsInRange(count, pageNumber, pageSize)){ // no point checking again
689
            if (logger.isDebugEnabled()){logger.debug(" get list ...");}
690
            descriptionElements = listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
691
        } else {
692
            descriptionElements = new ArrayList<T>(0);
693
        }
694
        if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
695
        return new DefaultPagerImpl<T>(pageNumber, count, pageSize, descriptionElements);
696
    }
697

    
698
    @Override
699
    public String generateNaturalLanguageDescription(TermTree featureTree,
700
            TaxonDescription description, List<Language> preferredLanguages, String separator) {
701

    
702
        Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
703

    
704
        description = (TaxonDescription)load(description.getUuid());
705
        featureTree = featureTreeDao.load(featureTree.getUuid());
706

    
707
        StringBuilder naturalLanguageDescription = new StringBuilder();
708

    
709
        MarkerType useMarkerType = (MarkerType) definedTermDao.load(UUID.fromString("2e6e42d9-e92a-41f4-899b-03c0ac64f039"));
710
        boolean isUseDescription = false;
711
        if(!description.getMarkers().isEmpty()) {
712
            for (Marker marker: description.getMarkers()) {
713
                MarkerType markerType = marker.getMarkerType();
714
                if (markerType.equals(useMarkerType)) {
715
                    isUseDescription = true;
716
                }
717

    
718
            }
719
        }
720

    
721
        if(description.hasStructuredData() && !isUseDescription){
722

    
723

    
724
            String lastCategory = null;
725
            String categorySeparator = ". ";
726

    
727
            List<TextData> textDataList;
728
            TextData naturalLanguageDescriptionText = null;
729

    
730
            boolean useMicroFormatQuantitativeDescriptionBuilder = false;
731

    
732
            if(useMicroFormatQuantitativeDescriptionBuilder){
733

    
734
                MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
735
                naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
736
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
737

    
738
            } else {
739

    
740
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
741
                        featureTree,
742
                        (description),
743
                        lang);
744
            }
745

    
746
            return naturalLanguageDescriptionText.getText(lang);
747

    
748
//
749
//			boolean doItBetter = false;
750
//
751
//			for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
752
//				if(textData.getMultilanguageText().size() > 0){
753
//
754
//					if (!textData.getFeature().equals(Feature.UNKNOWN())) {
755
//						String featureLabel = textData.getFeature().getLabel(lang);
756
//
757
//						if(doItBetter){
758
//							/*
759
//							 *  WARNING
760
//							 *  The code lines below are desinged to handle
761
//							 *  a special case where as the feature label contains
762
//							 *  hierarchical information on the features. This code
763
//							 *  exist only as a base for discussion, and is not
764
//							 *  intendet to be used in production.
765
//							 */
766
//							featureLabel = StringUtils.remove(featureLabel, '>');
767
//
768
//							String[] labelTokens = StringUtils.split(featureLabel, '<');
769
//							if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
770
//								if(naturalLanguageDescription.length() > 0){
771
//									naturalLanguageDescription.append(separator);
772
//								}
773
//								naturalLanguageDescription.append(labelTokens[1]);
774
//							} else {
775
//								if(naturalLanguageDescription.length() > 0){
776
//									naturalLanguageDescription.append(categorySeparator);
777
//								}
778
//								naturalLanguageDescription.append(StringUtils.join(labelTokens));
779
//							}
780
//							lastCategory = labelTokens[0];
781
//							// end of demo code
782
//						} else {
783
//							if(naturalLanguageDescription.length() > 0){
784
//								naturalLanguageDescription.append(separator);
785
//							}
786
//							naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
787
//						}
788
//					} else {
789
//						if(naturalLanguageDescription.length() > 0){
790
//							naturalLanguageDescription.append(separator);
791
//						}
792
//					}
793
//					String text = textData.getMultilanguageText().values().iterator().next().getText();
794
//					naturalLanguageDescription.append(text);
795
//
796
//				}
797
//			}
798

    
799
        }
800
        else if (isUseDescription) {
801
            //AT: Left Blank in case we need to generate a Natural language text string.
802
        }
803
        return naturalLanguageDescription.toString();
804
    }
805

    
806

    
807
    @Override
808
    public boolean hasStructuredData(DescriptionBase<?> description) {
809
        return load(description.getUuid()).hasStructuredData();
810
    }
811

    
812

    
813
    @Override
814
   // @Transactional(readOnly = false)
815
    public UpdateResult moveDescriptionElementsToDescription(
816
            Collection<DescriptionElementBase> descriptionElements,
817
            DescriptionBase targetDescription,
818
            boolean isCopy,
819
            boolean setNameInSource) {
820

    
821
        UpdateResult result = new UpdateResult();
822
        if (descriptionElements.isEmpty() || descriptionElements.iterator().next() == null){
823
            result.setAbort();
824
            return result;
825
        }
826

    
827

    
828
        if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
829
            //if the descriptionElements collection is the elements set of a description, put it in a separate set before to avoid concurrent modification exceptions
830
            descriptionElements = new HashSet<DescriptionElementBase>(descriptionElements);
831
//			descriptionElementsTmp.addAll(descriptionElements);
832
//			descriptionElements = descriptionElementsTmp;
833
        }
834
        for (DescriptionElementBase element : descriptionElements){
835
            DescriptionBase<?> description = element.getInDescription();
836
            description = HibernateProxyHelper.deproxy(dao.load(description.getUuid()));
837
            Taxon taxon;
838
            TaxonName name = null;
839
            if (description instanceof TaxonDescription){
840
                TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
841
                if (taxonDescription.getTaxon() != null){
842
                    taxon = (Taxon) taxonDao.load(taxonDescription.getTaxon().getUuid());
843
                    name = taxon.getName();
844
                }
845

    
846

    
847
            }
848
            try {
849
                DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
850
                if (setNameInSource) {
851
                    for (DescriptionElementSource source: newElement.getSources()){
852
                            if (source.getNameUsedInSource() == null){
853
                                source.setNameUsedInSource(name);
854
                            }
855
                        }
856

    
857
                }
858
                targetDescription.addElement(newElement);
859
            } catch (CloneNotSupportedException e) {
860
                throw new RuntimeException ("Clone not yet implemented for class " + element.getClass().getName(), e);
861
            }
862
            if (! isCopy){
863
                description.removeElement(element);
864
                dao.saveOrUpdate(description);
865
                result.addUpdatedObject(description);
866
//                if (description.getElements().isEmpty()){
867
//                   if (description instanceof TaxonDescription){
868
//                       TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
869
//                       if (taxDescription.getTaxon() != null){
870
//                           taxDescription.getTaxon().removeDescription((TaxonDescription)description);
871
//                       }
872
//                   }
873
//                    dao.delete(description);
874
//
875
//                }//else{
876
//                    dao.saveOrUpdate(description);
877
//                    result.addUpdatedObject(description);
878
//                }
879
            }
880

    
881

    
882
        }
883
        dao.saveOrUpdate(targetDescription);
884
        result.addUpdatedObject(targetDescription);
885
        if (targetDescription instanceof TaxonDescription){
886
            result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
887
        }
888
        return result;
889
    }
890

    
891
    @Override
892
    @Transactional(readOnly = false)
893
    public UpdateResult moveDescriptionElementsToDescription(
894
            Set<UUID> descriptionElementUUIDs,
895
            UUID targetDescriptionUuid,
896
            boolean isCopy, boolean setNameInSource) {
897
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
898
        for(UUID deUuid : descriptionElementUUIDs) {
899
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
900
            if (element != null){
901
                descriptionElements.add(element);
902
            }
903
        }
904
        DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
905

    
906
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
907
    }
908

    
909
    @Override
910
    @Transactional(readOnly = false)
911
    public UpdateResult moveDescriptionElementsToDescription(
912
            Set<UUID> descriptionElementUUIDs,
913
            DescriptionBase targetDescription,
914
            boolean isCopy, boolean setNameInSource) {
915
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
916
        for(UUID deUuid : descriptionElementUUIDs) {
917
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
918
            if (element != null){
919
                descriptionElements.add(element);
920
            }
921
        }
922
        DescriptionBase newTargetDescription;
923
        if (targetDescription.isPersited()){
924
            newTargetDescription = dao.load(targetDescription.getUuid());
925
        }else{
926
            if (targetDescription instanceof TaxonDescription){
927
                Taxon taxon = (Taxon)taxonDao.load(((TaxonDescription)targetDescription).getTaxon().getUuid());
928

    
929
                newTargetDescription = TaxonDescription.NewInstance(taxon, targetDescription.isImageGallery());
930

    
931
            }else if (targetDescription instanceof TaxonNameDescription){
932
                TaxonName name = nameDao.load(((TaxonNameDescription)targetDescription).getTaxonName().getUuid());
933
                newTargetDescription = TaxonNameDescription.NewInstance(name);
934
            }else {
935
                SpecimenOrObservationBase specimen = occurrenceDao.load(((SpecimenDescription)targetDescription).getDescribedSpecimenOrObservation().getUuid());
936
                newTargetDescription = SpecimenDescription.NewInstance(specimen);
937
            }
938

    
939
            newTargetDescription.addSources(targetDescription.getSources());
940
            newTargetDescription.setTitleCache(targetDescription.getTitleCache(), targetDescription.isProtectedTitleCache());
941

    
942
        }
943
        return moveDescriptionElementsToDescription(descriptionElements, newTargetDescription, isCopy, setNameInSource);
944
    }
945

    
946

    
947
    @Override
948
    @Transactional(readOnly = false)
949
    public UpdateResult moveDescriptionElementsToDescription(
950
            Set<UUID> descriptionElementUUIDs,
951
            UUID targetTaxonUuid,
952
            String moveMessage,
953
            boolean isCopy, boolean setNameInSource) {
954
        Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
955
        DescriptionBase targetDescription = TaxonDescription.NewInstance(targetTaxon);
956
        targetDescription.setTitleCache(moveMessage, true);
957
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
958
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
959
        targetDescription.addAnnotation(annotation);
960

    
961
        targetDescription = dao.save(targetDescription);
962
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
963
        for(UUID deUuid : descriptionElementUUIDs) {
964
            descriptionElements.add(descriptionElementDao.load(deUuid));
965
        }
966

    
967
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
968
    }
969

    
970
    @Override
971
    public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
972
            Integer pageNumber){
973
        List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
974
        int startIndex= pageNumber * pageSize;
975
        int toIndex = Math.min(startIndex + pageSize, results.size());
976
        List<TermDto> page = results.subList(startIndex, toIndex);
977
        return new DefaultPagerImpl<TermDto>(pageNumber, results.size(), pageSize, page);
978
    }
979

    
980

    
981
    @Override
982
    @Transactional(readOnly = false)
983
    public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon, boolean setNameInSource) {
984
        List<TaxonDescription> descriptions = new ArrayList<>(sourceTaxon.getDescriptions());
985
        UpdateResult result = new UpdateResult();
986
        result.addUpdatedObject(sourceTaxon);
987
        result.addUpdatedObject(targetTaxon);
988
        for(TaxonDescription description : descriptions){
989
            targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
990
        }
991
        return result;
992
    }
993

    
994
    private TaxonDescription prepareDescriptionForMove(TaxonDescription description, Taxon sourceTaxon, boolean setNameInSource){
995
        String moveMessage = String.format("Description moved from %s", sourceTaxon);
996
        if(description.isProtectedTitleCache()){
997
            String separator = "";
998
            if(!StringUtils.isBlank(description.getTitleCache())){
999
                separator = " - ";
1000
            }
1001
            description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
1002
        }
1003
        else{
1004
            description.setTitleCache(moveMessage, true);
1005
        }
1006
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
1007
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
1008
        description.addAnnotation(annotation);
1009
        if(setNameInSource){
1010
            for (DescriptionElementBase element: description.getElements()){
1011
                for (DescriptionElementSource source: element.getSources()){
1012
                    if (source.getNameUsedInSource() == null){
1013
                        source.setNameUsedInSource(sourceTaxon.getName());
1014
                    }
1015
                }
1016
            }
1017
        }
1018
        return description;
1019
    }
1020

    
1021
    @Override
1022
    @Transactional(readOnly = false)
1023
    public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid, boolean setNameInSource) {
1024
        Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
1025
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
1026
        return moveTaxonDescriptions(sourceTaxon, targetTaxon, setNameInSource);
1027

    
1028
    }
1029

    
1030
    @Override
1031
    @Transactional(readOnly = false)
1032
    public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid, boolean setNameInSource){
1033
        TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
1034
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
1035
        Taxon sourceTaxon = description.getTaxon();
1036
        UpdateResult result = new UpdateResult();
1037
        result.addUpdatedObject(sourceTaxon);
1038
        result.addUpdatedObject(targetTaxon);
1039

    
1040
        targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
1041
        return result;
1042

    
1043
    }
1044

    
1045

    
1046
}
(11-11/100)