Project

General

Profile

Download (43.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

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

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

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

    
94
    private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
95

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

    
109
    //TODO change to Interface
110
    private NaturalLanguageGenerator naturalLanguageGenerator;
111

    
112
    @Autowired
113
    protected void setFeatureTreeDao(ITermTreeDao featureTreeDao) {
114
        this.featureTreeDao = featureTreeDao;
115
    }
116

    
117
    @Autowired
118
    protected void setDescriptiveDataSetDao(IDescriptiveDataSetDao descriptiveDataSetDao) {
119
        this.descriptiveDataSetDao = descriptiveDataSetDao;
120
    }
121

    
122
    @Autowired
123
    protected void setTermNodeDao(ITermNodeDao featureNodeDao) {
124
        this.termNodeDao = featureNodeDao;
125
    }
126

    
127
    @Autowired
128
    protected void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
129
        this.vocabularyDao = vocabularyDao;
130
    }
131

    
132
    @Autowired
133
    protected void setDefinedTermDao(IDefinedTermDao definedTermDao) {
134
        this.definedTermDao = definedTermDao;
135
    }
136

    
137
    @Autowired
138
    protected void statisticalMeasurementValueDao(IStatisticalMeasurementValueDao statisticalMeasurementValueDao) {
139
        this.statisticalMeasurementValueDao = statisticalMeasurementValueDao;
140
    }
141

    
142
    @Autowired
143
    protected void setDescriptionElementDao(IDescriptionElementDao descriptionElementDao) {
144
        this.descriptionElementDao = descriptionElementDao;
145
    }
146

    
147
    @Autowired
148
    protected void setNaturalLanguageGenerator(NaturalLanguageGenerator naturalLanguageGenerator) {
149
        this.naturalLanguageGenerator = naturalLanguageGenerator;
150
    }
151

    
152
    @Autowired
153
    protected void setTaxonDao(ITaxonDao taxonDao) {
154
        this.taxonDao = taxonDao;
155
    }
156

    
157
    @Autowired
158
    protected void setTaxonNodeDao(ITaxonNodeDao taxonNodeDao) {
159
        this.taxonNodeDao = taxonNodeDao;
160
    }
161

    
162
    @Autowired
163
    protected void setDataSetDao(IDescriptiveDataSetDao dataSetDao) {
164
        this.dataSetDao = dataSetDao;
165
    }
166

    
167
    public DescriptionServiceImpl() {
168
        logger.debug("Load DescriptionService Bean");
169
    }
170

    
171
    @Override
172
    @Transactional(readOnly = false)
173
    public UpdateResult updateCaches(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
174
        if (clazz == null){
175
            clazz = DescriptionBase.class;
176
        }
177
        return super.updateCachesImpl(clazz, stepSize, cacheStrategy, monitor);
178
    }
179

    
180
    @Override
181
    public TermVocabulary<Feature> getDefaultFeatureVocabulary(){
182
        String uuidFeature = "b187d555-f06f-4d65-9e53-da7c93f8eaa8";
183
        UUID featureUuid = UUID.fromString(uuidFeature);
184
        return vocabularyDao.findByUuid(featureUuid);
185
    }
186

    
187
    @Override
188
    @Autowired
189
    protected void setDao(IDescriptionDao dao) {
190
        this.dao = dao;
191
    }
192

    
193
    @Override
194
    public long count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
195
        return dao.countDescriptions(type, hasImages, hasText, feature);
196
    }
197

    
198
    @Override
199
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
200
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
201

    
202
        List<T> results = listDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
203
        return new DefaultPagerImpl<>(pageNumber, Integer.valueOf(results.size()).longValue(), pageSize, results);
204
    }
205

    
206
    @Override
207
    @Deprecated
208
    public <T extends DescriptionElementBase> Pager<T> getDescriptionElements(DescriptionBase description,
209
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
210
        return pageDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
211
    }
212

    
213
    @Override
214
    public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
215
            Class<? extends DescriptionBase> descriptionType, Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber,
216
            List<String> propertyPaths) {
217

    
218
        long numberOfResults = dao.countDescriptionElements(description, descriptionType, features, type);
219
        List<T> results = new ArrayList<T>();
220
        if(AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)) {
221
            results = dao.getDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
222
        }
223
        return results;
224
    }
225

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

    
231
        return listDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
232
    }
233

    
234
    @Override
235
    public Pager<Annotation> getDescriptionElementAnnotations(DescriptionElementBase annotatedObj, MarkerType status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
236
        long numberOfResults = descriptionElementDao.countAnnotations(annotatedObj, status);
237

    
238
        List<Annotation> results = new ArrayList<>();
239
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
240
            results = descriptionElementDao.getAnnotations(annotatedObj, status, pageSize, pageNumber, orderHints, propertyPaths);
241
        }
242

    
243
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
244
    }
245

    
246

    
247
    @Override
248
    public Pager<Media> getMedia(DescriptionElementBase descriptionElement,	Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
249
        Long numberOfResults = descriptionElementDao.countMedia(descriptionElement);
250

    
251
        List<Media> results = new ArrayList<Media>();
252
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
253
            results = descriptionElementDao.getMedia(descriptionElement, pageSize, pageNumber, propertyPaths);
254
        }
255

    
256
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
257
    }
258

    
259
    @Override
260
    public Pager<TaxonDescription> pageTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
261
        Set<MarkerType> markerTypes = null;
262
        Set<DescriptionType> descriptionTypes = null;
263
        return pageTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
264
    }
265

    
266
    @Override
267
    public List<TaxonDescription> listTaxonDescriptions(Taxon taxon, Set<DefinedTerm> scopes, Set<NamedArea> geographicalScope, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
268
        Set<MarkerType> markerTypes = null;
269
        Set<DescriptionType> descriptionTypes = null;
270
        return listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
271
    }
272

    
273
    @Override
274
    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) {
275
        long numberOfResults = dao.countTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes);
276

    
277
        List<TaxonDescription> results = new ArrayList<>();
278
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
279
            results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
280
        }
281

    
282
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
283
    }
284

    
285
    @Override
286
    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) {
287
        List<TaxonDescription> results = dao.listTaxonDescriptions(taxon, scopes, geographicalScope, markerTypes, descriptionTypes, pageSize, pageNumber, propertyPaths);
288
        return results;
289
    }
290

    
291

    
292
    @Override
293
    public List<Media> listTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths){
294
        return this.dao.listTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes, pageSize, pageNumber, propertyPaths);
295
    }
296

    
297
    @Override
298
    public int countTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes){
299
        return this.dao.countTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes);
300
    }
301

    
302
    @Override
303
    public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
304
        long numberOfResults = dao.countTaxonNameDescriptions(name);
305

    
306
        List<TaxonNameDescription> results = new ArrayList<>();
307
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
308
            results = dao.getTaxonNameDescriptions(name, pageSize, pageNumber,propertyPaths);
309
        }
310

    
311
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
312
    }
313

    
314

    
315
    @Override
316
    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) {
317
        long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
318

    
319
        @SuppressWarnings("rawtypes")
320
        List<DescriptionBase> results = new ArrayList<>();
321
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
322
            results = dao.listDescriptions(type, hasImages, hasText, feature, pageSize, pageNumber,orderHints,propertyPaths);
323
        }
324

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

    
328
    /**
329
     * FIXME Candidate for harmonization
330
     * Rename: searchByDistribution
331
     */
332
    @Override
333
    public Pager<TaxonDescription> searchDescriptionByDistribution(Set<NamedArea> namedAreas, PresenceAbsenceTerm presence,	Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
334
        long numberOfResults = dao.countDescriptionByDistribution(namedAreas, presence);
335

    
336
        List<TaxonDescription> results = new ArrayList<>();
337
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
338
            results = dao.searchDescriptionByDistribution(namedAreas, presence, pageSize, pageNumber,orderHints,propertyPaths);
339
        }
340

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

    
344
    /**
345
     * FIXME Candidate for harmonization
346
     * move: descriptionElementService.search
347
     */
348
    @Override
349
//    public Pager<T> searchElements(Class<? extends T> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
350
    public <S extends DescriptionElementBase> Pager<S> searchElements(Class<S> clazz, String queryString, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
351
        long numberOfResults = descriptionElementDao.count(clazz, queryString);
352

    
353
        List<S> results = new ArrayList<>();
354
        if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
355
            results = (List<S>)descriptionElementDao.search(clazz, queryString, pageSize, pageNumber, orderHints, propertyPaths);
356
        }
357

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

    
361
    /**
362
     * FIXME Candidate for harmonization
363
     * descriptionElementService.find
364
     */
365
    @Override
366
    public DescriptionElementBase getDescriptionElementByUuid(UUID uuid) {
367
        return descriptionElementDao.findByUuid(uuid);
368
    }
369

    
370
    /**
371
     * FIXME Candidate for harmonization
372
     * descriptionElementService.load
373
     */
374
    @Override
375
    public DescriptionElementBase loadDescriptionElement(UUID uuid,	List<String> propertyPaths) {
376
        return descriptionElementDao.load(uuid, propertyPaths);
377
    }
378

    
379
    /**
380
     * FIXME Candidate for harmonization
381
     * descriptionElementService.save
382
     */
383
    @Override
384
    @Transactional(readOnly = false)
385
    public UUID saveDescriptionElement(DescriptionElementBase descriptionElement) {
386
        return descriptionElementDao.save(descriptionElement).getUuid();
387
    }
388

    
389
    /**
390
     * FIXME Candidate for harmonization
391
     * descriptionElementService.save
392
     */
393
    @Override
394
    @Transactional(readOnly = false)
395
    public Map<UUID, DescriptionElementBase> saveDescriptionElement(Collection<DescriptionElementBase> descriptionElements) {
396
        return descriptionElementDao.saveAll(descriptionElements);
397
    }
398

    
399
    @Override
400
    @Transactional(readOnly = false)
401
    public List<MergeResult<DescriptionBase>> mergeDescriptionElements(Collection<TaxonDistributionDTO> descriptionElements, boolean returnTransientEntity) {
402
        List<MergeResult<DescriptionBase>> mergedObjects = new ArrayList();
403

    
404
        for(TaxonDistributionDTO obj : descriptionElements) {
405
            Iterator<TaxonDescription> iterator = obj.getDescriptionsWrapper().getDescriptions().iterator();
406
            List<DescriptionBase> list = new ArrayList(obj.getDescriptionsWrapper().getDescriptions());
407
          //  Map<UUID, DescriptionBase> map = dao.saveOrUpdateAll(list);
408
//            MergeResult<DescriptionBase> mergeResult = new MergeResult<DescriptionBase>(mergedEntity, newEntities)
409
//            mergedObjects.add(map.values());
410
            while (iterator.hasNext()){
411
                TaxonDescription desc = iterator.next();
412
                mergedObjects.add(dao.merge(desc, returnTransientEntity));
413
            }
414

    
415

    
416
        }
417

    
418
        return mergedObjects;
419
    }
420
//
421
    @Override
422
    @Transactional(readOnly = false)
423
    public UpdateResult mergeDescriptions(Collection<DescriptionBaseDto> descriptions, UUID descriptiveDataSetUuid) {
424
//        List<<DescriptionBase>> mergedObjects = new ArrayList();
425
        UpdateResult result = new UpdateResult();
426
        DescriptiveDataSet dataSet = descriptiveDataSetDao.load(descriptiveDataSetUuid);
427
        Set<DescriptionBase> descriptionsOfDataSet = dataSet.getDescriptions();
428
        HashMap<UUID, DescriptionBase> descriptionSpecimenMap = new HashMap();
429

    
430
        for (DescriptionBase descriptionBase: descriptionsOfDataSet){
431
            if (descriptionBase.getDescribedSpecimenOrObservation() != null){
432
                descriptionSpecimenMap.put(descriptionBase.getDescribedSpecimenOrObservation().getUuid(), descriptionBase);
433
            }
434
        }
435
        MergeResult<DescriptionBase> mergeResult = null;
436
        for(DescriptionBaseDto descDto : descriptions) {
437
            DescriptionBase description = descDto.getDescription();
438
            UUID describedObjectUuid = null;
439
            if (description instanceof SpecimenDescription){
440
                describedObjectUuid = descDto.getSpecimenDto().getUuid();
441
            }else if (description instanceof TaxonDescription){
442
                describedObjectUuid = descDto.getTaxonDto().getUuid();
443
            }else if (description instanceof TaxonNameDescription){
444
                describedObjectUuid = descDto.getNameDto().getUuid();
445
            }
446
            if (descriptionSpecimenMap.get(describedObjectUuid) != null && !descriptionSpecimenMap.get(describedObjectUuid).equals(description)){
447
                Set<DescriptionElementBase> elements = new HashSet();
448
                for (Object element: description.getElements()){
449
                    elements.add((DescriptionElementBase)element);
450
                }
451
                DescriptionBase desc = descriptionSpecimenMap.get(describedObjectUuid);
452
//                description.setDescribedSpecimenOrObservation(null);
453

    
454
                for (DescriptionElementBase element: elements){
455
                    desc.addElement(element);
456
                }
457
                descriptionSpecimenMap.put(describedObjectUuid, desc);
458
                description = desc;
459
            }
460
            try{
461
                mergeResult = dao.merge(description, true);
462
                result.addUpdatedObject( mergeResult.getMergedEntity());
463
//                if (description instanceof SpecimenDescription){
464
//                    result.addUpdatedObject(mergeResult.getMergedEntity().getDescribedSpecimenOrObservation());
465
//                }else if (description instanceof TaxonDescription){
466
//                    result.addUpdatedObject(((TaxonDescription)mergeResult.getMergedEntity()).getTaxon());
467
//                }else if (description instanceof TaxonNameDescription){
468
//                    result.addUpdatedObject(((TaxonNameDescription)mergeResult.getMergedEntity()).getTaxonName());
469
//                }
470
            }catch(Exception e){
471
                e.printStackTrace();
472
            }
473

    
474
        }
475

    
476
        return result;
477
    }
478

    
479
    /**
480
     * FIXME Candidate for harmonization
481
     * descriptionElementService.delete
482
     */
483
    @Override
484
    public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
485
        return descriptionElementDao.delete(descriptionElement);
486
    }
487

    
488
    @Override
489
    public UUID deleteDescriptionElement(UUID descriptionElementUuid) {
490
        return deleteDescriptionElement(descriptionElementDao.load(descriptionElementUuid));
491
    }
492

    
493
    @Override
494
    @Transactional(readOnly = false)
495
    public DeleteResult deleteDescription(DescriptionBase description) {
496

    
497
        DeleteResult deleteResult = new DeleteResult();
498
        if (description == null){
499
            return deleteResult;
500
        }
501
        description = load(description.getId(), Arrays.asList("descriptiveDataSets"));
502
        //avoid lazy init exception
503

    
504
        deleteResult = isDeletable(description.getUuid());
505
        if (deleteResult.getRelatedObjects() != null && deleteResult.getRelatedObjects().size() == 1){
506
            Iterator<CdmBase> relObjects = deleteResult.getRelatedObjects().iterator();
507
            CdmBase next = relObjects.next();
508
            if (next instanceof CdmLinkSource){
509
                CdmLinkSource source = (CdmLinkSource)next;
510
                ICdmTarget target = source.getTarget();
511

    
512

    
513
            }
514
        }
515
        if (deleteResult.isOk() ){
516
        	if (description instanceof TaxonDescription){
517
        		TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
518
        		Taxon tax = taxDescription.getTaxon();
519
        		tax.removeDescription(taxDescription, true);
520
                deleteResult.addUpdatedObject(tax);
521
        	}
522
        	else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
523
        	    SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(description, SpecimenDescription.class);
524
        	    SpecimenOrObservationBase<?> specimen = specimenDescription.getDescribedSpecimenOrObservation();
525
        	    specimen.removeDescription(specimenDescription);
526
        	    deleteResult.addUpdatedObject(specimen);
527
        	}
528

    
529
        	Set<DescriptiveDataSet> descriptiveDataSets = description.getDescriptiveDataSets();
530
        	for (Iterator<DescriptiveDataSet> iterator = descriptiveDataSets.iterator(); iterator.hasNext();) {
531
        	    iterator.next().removeDescription(description);
532
            }
533

    
534
        	dao.delete(description);
535
        	deleteResult.addDeletedObject(description);
536
        	deleteResult.setCdmEntity(description);
537
        }else{
538
            logger.info(deleteResult.getExceptions().toString());
539
        }
540

    
541
        return deleteResult;
542
    }
543

    
544
    @Override
545
    @Transactional(readOnly = false)
546
    public DeleteResult deleteDescription(UUID descriptionUuid) {
547
        return deleteDescription(dao.load(descriptionUuid));
548
    }
549

    
550
    @Override
551
    public DeleteResult isDeletable(UUID descriptionUuid){
552
        DeleteResult result = new DeleteResult();
553
        DescriptionBase<?> description = this.load(descriptionUuid);
554
        Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(description);
555

    
556
        if (references == null || references.isEmpty()){
557
            return result;
558
        }
559
        for (CdmBase ref: references){
560
            String message = null;
561
            if (description instanceof TaxonDescription && ref instanceof Taxon && ((TaxonDescription)description).getTaxon().equals(ref)){
562
                continue;
563
            } else if (description instanceof TaxonNameDescription && ref instanceof TaxonName && ((TaxonNameDescription)description).getTaxonName().equals(ref)){
564
                continue;
565
            } else if (description instanceof SpecimenDescription && ref instanceof SpecimenOrObservationBase && ((SpecimenDescription)description).getDescribedSpecimenOrObservation().equals(ref)){
566
                continue;
567
            } else if (ref instanceof DescriptionElementBase){
568
                continue;
569
            }else {
570
                message = "The description can't be completely deleted because it is referenced by " + ref.getUserFriendlyTypeName() ;
571
                result.setAbort();
572
            }
573
            if (message != null){
574
                result.addException(new ReferencedObjectUndeletableException(message));
575
                result.addRelatedObject(ref);
576
            }
577
        }
578

    
579
        return result;
580
    }
581

    
582
    @Override
583
    public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
584
        return vocabularyDao.findByUuid(uuid);
585
    }
586

    
587
    @Override
588
    @Deprecated
589
    public <T extends DescriptionElementBase> List<T> getDescriptionElementsForTaxon(
590
            Taxon taxon, Set<Feature> features,
591
            Class<T> type, Integer pageSize,
592
            Integer pageNumber, List<String> propertyPaths) {
593
        return listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
594
    }
595

    
596
    @Override
597
    public <T extends DescriptionElementBase> List<T> listDescriptionElementsForTaxon(
598
            Taxon taxon, Set<Feature> features,
599
            Class<T> type, Integer pageSize,
600
            Integer pageNumber, List<String> propertyPaths) {
601
        return dao.getDescriptionElementForTaxon(taxon.getUuid(), features, type, pageSize, pageNumber, propertyPaths);
602
    }
603

    
604
    @Override
605
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElementsForTaxon(
606
            Taxon taxon, Set<Feature> features,
607
            Class<T> type, Integer pageSize,
608
            Integer pageNumber, List<String> propertyPaths) {
609
        if (logger.isDebugEnabled()){logger.debug(" get count ...");}
610
        Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type);
611
        List<T> descriptionElements;
612
        if(AbstractPagerImpl.hasResultsInRange(count, pageNumber, pageSize)){ // no point checking again
613
            if (logger.isDebugEnabled()){logger.debug(" get list ...");}
614
            descriptionElements = listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
615
        } else {
616
            descriptionElements = new ArrayList<T>(0);
617
        }
618
        if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
619
        return new DefaultPagerImpl<T>(pageNumber, count, pageSize, descriptionElements);
620
    }
621

    
622
    @Override
623
    public String generateNaturalLanguageDescription(TermTree featureTree,
624
            TaxonDescription description, List<Language> preferredLanguages, String separator) {
625

    
626
        Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
627

    
628
        description = (TaxonDescription)load(description.getUuid());
629
        featureTree = featureTreeDao.load(featureTree.getUuid());
630

    
631
        StringBuilder naturalLanguageDescription = new StringBuilder();
632

    
633
        MarkerType useMarkerType = (MarkerType) definedTermDao.load(UUID.fromString("2e6e42d9-e92a-41f4-899b-03c0ac64f039"));
634
        boolean isUseDescription = false;
635
        if(!description.getMarkers().isEmpty()) {
636
            for (Marker marker: description.getMarkers()) {
637
                MarkerType markerType = marker.getMarkerType();
638
                if (markerType.equals(useMarkerType)) {
639
                    isUseDescription = true;
640
                }
641

    
642
            }
643
        }
644

    
645
        if(description.hasStructuredData() && !isUseDescription){
646

    
647

    
648
            String lastCategory = null;
649
            String categorySeparator = ". ";
650

    
651
            List<TextData> textDataList;
652
            TextData naturalLanguageDescriptionText = null;
653

    
654
            boolean useMicroFormatQuantitativeDescriptionBuilder = false;
655

    
656
            if(useMicroFormatQuantitativeDescriptionBuilder){
657

    
658
                MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
659
                naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
660
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
661

    
662
            } else {
663

    
664
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
665
                        featureTree,
666
                        (description),
667
                        lang);
668
            }
669

    
670
            return naturalLanguageDescriptionText.getText(lang);
671

    
672
//
673
//			boolean doItBetter = false;
674
//
675
//			for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
676
//				if(textData.getMultilanguageText().size() > 0){
677
//
678
//					if (!textData.getFeature().equals(Feature.UNKNOWN())) {
679
//						String featureLabel = textData.getFeature().getLabel(lang);
680
//
681
//						if(doItBetter){
682
//							/*
683
//							 *  WARNING
684
//							 *  The code lines below are desinged to handle
685
//							 *  a special case where as the feature label contains
686
//							 *  hierarchical information on the features. This code
687
//							 *  exist only as a base for discussion, and is not
688
//							 *  intendet to be used in production.
689
//							 */
690
//							featureLabel = StringUtils.remove(featureLabel, '>');
691
//
692
//							String[] labelTokens = StringUtils.split(featureLabel, '<');
693
//							if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
694
//								if(naturalLanguageDescription.length() > 0){
695
//									naturalLanguageDescription.append(separator);
696
//								}
697
//								naturalLanguageDescription.append(labelTokens[1]);
698
//							} else {
699
//								if(naturalLanguageDescription.length() > 0){
700
//									naturalLanguageDescription.append(categorySeparator);
701
//								}
702
//								naturalLanguageDescription.append(StringUtils.join(labelTokens));
703
//							}
704
//							lastCategory = labelTokens[0];
705
//							// end of demo code
706
//						} else {
707
//							if(naturalLanguageDescription.length() > 0){
708
//								naturalLanguageDescription.append(separator);
709
//							}
710
//							naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
711
//						}
712
//					} else {
713
//						if(naturalLanguageDescription.length() > 0){
714
//							naturalLanguageDescription.append(separator);
715
//						}
716
//					}
717
//					String text = textData.getMultilanguageText().values().iterator().next().getText();
718
//					naturalLanguageDescription.append(text);
719
//
720
//				}
721
//			}
722

    
723
        }
724
        else if (isUseDescription) {
725
            //AT: Left Blank in case we need to generate a Natural language text string.
726
        }
727
        return naturalLanguageDescription.toString();
728
    }
729

    
730

    
731
    @Override
732
    public boolean hasStructuredData(DescriptionBase<?> description) {
733
        return load(description.getUuid()).hasStructuredData();
734
    }
735

    
736

    
737
    @Override
738
   // @Transactional(readOnly = false)
739
    public UpdateResult moveDescriptionElementsToDescription(
740
            Collection<DescriptionElementBase> descriptionElements,
741
            DescriptionBase targetDescription,
742
            boolean isCopy,
743
            boolean setNameInSource) {
744

    
745
        UpdateResult result = new UpdateResult();
746
        if (descriptionElements.isEmpty() || descriptionElements.iterator().next() == null){
747
            result.setAbort();
748
            return result;
749
        }
750

    
751

    
752
        if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
753
            //if the descriptionElements collection is the elements set of a description, put it in a separate set before to avoid concurrent modification exceptions
754
            descriptionElements = new HashSet<DescriptionElementBase>(descriptionElements);
755
//			descriptionElementsTmp.addAll(descriptionElements);
756
//			descriptionElements = descriptionElementsTmp;
757
        }
758
        for (DescriptionElementBase element : descriptionElements){
759
            DescriptionBase<?> description = element.getInDescription();
760
            description = HibernateProxyHelper.deproxy(dao.load(description.getUuid()));
761
            Taxon taxon;
762
            TaxonName name = null;
763
            if (description instanceof TaxonDescription){
764
                TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
765
                if (taxonDescription.getTaxon() != null){
766
                    taxon = (Taxon) taxonDao.load(taxonDescription.getTaxon().getUuid());
767
                    name = taxon.getName();
768
                }
769

    
770

    
771
            }
772
            try {
773
                DescriptionElementBase newElement = element.clone();
774
                if (setNameInSource) {
775
                    for (DescriptionElementSource source: newElement.getSources()){
776
                            if (source.getNameUsedInSource() == null){
777
                                source.setNameUsedInSource(name);
778
                            }
779
                        }
780

    
781
                }
782
                targetDescription.addElement(newElement);
783
            } catch (CloneNotSupportedException e) {
784
                throw new RuntimeException ("Clone not yet implemented for class " + element.getClass().getName(), e);
785
            }
786
            if (! isCopy){
787
                description.removeElement(element);
788
                dao.saveOrUpdate(description);
789
                result.addUpdatedObject(description);
790
//                if (description.getElements().isEmpty()){
791
//                   if (description instanceof TaxonDescription){
792
//                       TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
793
//                       if (taxDescription.getTaxon() != null){
794
//                           taxDescription.getTaxon().removeDescription((TaxonDescription)description);
795
//                       }
796
//                   }
797
//                    dao.delete(description);
798
//
799
//                }//else{
800
//                    dao.saveOrUpdate(description);
801
//                    result.addUpdatedObject(description);
802
//                }
803
            }
804

    
805

    
806
        }
807
        dao.saveOrUpdate(targetDescription);
808
        result.addUpdatedObject(targetDescription);
809
        if (targetDescription instanceof TaxonDescription){
810
            result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
811
        }
812
        return result;
813
    }
814

    
815
    @Override
816
    @Transactional(readOnly = false)
817
    public UpdateResult moveDescriptionElementsToDescription(
818
            Set<UUID> descriptionElementUUIDs,
819
            UUID targetDescriptionUuid,
820
            boolean isCopy, boolean setNameInSource) {
821
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
822
        for(UUID deUuid : descriptionElementUUIDs) {
823
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
824
            if (element != null){
825
                descriptionElements.add(element);
826
            }
827
        }
828
        DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
829

    
830
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
831
    }
832

    
833
    @Override
834
    @Transactional(readOnly = false)
835
    public UpdateResult moveDescriptionElementsToDescription(
836
            Set<UUID> descriptionElementUUIDs,
837
            DescriptionBase targetDescription,
838
            boolean isCopy, boolean setNameInSource) {
839
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
840
        for(UUID deUuid : descriptionElementUUIDs) {
841
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
842
            if (element != null){
843
                descriptionElements.add(element);
844
            }
845
        }
846
        DescriptionBase newTargetDescription;
847
        if (targetDescription.isPersited()){
848
            newTargetDescription = dao.load(targetDescription.getUuid());
849
        }else{
850
            if (targetDescription instanceof TaxonDescription){
851
                Taxon taxon = (Taxon)taxonDao.load(((TaxonDescription)targetDescription).getTaxon().getUuid());
852

    
853
                newTargetDescription = TaxonDescription.NewInstance(taxon, targetDescription.isImageGallery());
854

    
855
            }else if (targetDescription instanceof TaxonNameDescription){
856
                TaxonName name = nameDao.load(((TaxonNameDescription)targetDescription).getTaxonName().getUuid());
857
                newTargetDescription = TaxonNameDescription.NewInstance(name);
858
            }else {
859
                SpecimenOrObservationBase specimen = occurrenceDao.load(((SpecimenDescription)targetDescription).getDescribedSpecimenOrObservation().getUuid());
860
                newTargetDescription = SpecimenDescription.NewInstance(specimen);
861
            }
862

    
863
            newTargetDescription.addSources(targetDescription.getSources());
864
            newTargetDescription.setTitleCache(targetDescription.getTitleCache(), targetDescription.isProtectedTitleCache());
865

    
866
        }
867
        return moveDescriptionElementsToDescription(descriptionElements, newTargetDescription, isCopy, setNameInSource);
868
    }
869

    
870

    
871
    @Override
872
    @Transactional(readOnly = false)
873
    public UpdateResult moveDescriptionElementsToDescription(
874
            Set<UUID> descriptionElementUUIDs,
875
            UUID targetTaxonUuid,
876
            String moveMessage,
877
            boolean isCopy, boolean setNameInSource) {
878
        Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
879
        DescriptionBase targetDescription = TaxonDescription.NewInstance(targetTaxon);
880
        targetDescription.setTitleCache(moveMessage, true);
881
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
882
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
883
        targetDescription.addAnnotation(annotation);
884

    
885
        targetDescription = dao.save(targetDescription);
886
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
887
        for(UUID deUuid : descriptionElementUUIDs) {
888
            descriptionElements.add(descriptionElementDao.load(deUuid));
889
        }
890

    
891
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy, setNameInSource);
892
    }
893

    
894
    @Override
895
    public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
896
            Integer pageIndex){
897
        List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
898
        List<TermDto> subList = PagerUtils.pageList(results, pageIndex, pageSize);
899
        return new DefaultPagerImpl<TermDto>(pageIndex, results.size(), pageSize, subList);
900
    }
901

    
902

    
903
    @Override
904
    @Transactional(readOnly = false)
905
    public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon, boolean setNameInSource) {
906
        List<TaxonDescription> descriptions = new ArrayList<>(sourceTaxon.getDescriptions());
907
        UpdateResult result = new UpdateResult();
908
        result.addUpdatedObject(sourceTaxon);
909
        result.addUpdatedObject(targetTaxon);
910
        for(TaxonDescription description : descriptions){
911
            targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
912
        }
913
        return result;
914
    }
915

    
916
    private TaxonDescription prepareDescriptionForMove(TaxonDescription description, Taxon sourceTaxon, boolean setNameInSource){
917
        String moveMessage = String.format("Description moved from %s", sourceTaxon);
918
        if(description.isProtectedTitleCache()){
919
            String separator = "";
920
            if(!StringUtils.isBlank(description.getTitleCache())){
921
                separator = " - ";
922
            }
923
            description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
924
        }
925
        else{
926
            description.setTitleCache(moveMessage, true);
927
        }
928
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
929
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
930
        description.addAnnotation(annotation);
931
        if(setNameInSource){
932
            for (DescriptionElementBase element: description.getElements()){
933
                for (DescriptionElementSource source: element.getSources()){
934
                    if (source.getNameUsedInSource() == null){
935
                        source.setNameUsedInSource(sourceTaxon.getName());
936
                    }
937
                }
938
            }
939
        }
940
        return description;
941
    }
942

    
943
    @Override
944
    @Transactional(readOnly = false)
945
    public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid, boolean setNameInSource) {
946
        Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
947
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
948
        return moveTaxonDescriptions(sourceTaxon, targetTaxon, setNameInSource);
949

    
950
    }
951

    
952
    @Override
953
    @Transactional(readOnly = false)
954
    public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid, boolean setNameInSource){
955
        TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
956
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
957
        Taxon sourceTaxon = description.getTaxon();
958
        UpdateResult result = new UpdateResult();
959
        result.addUpdatedObject(sourceTaxon);
960
        result.addUpdatedObject(targetTaxon);
961

    
962
        targetTaxon.addDescription(prepareDescriptionForMove(description, sourceTaxon, setNameInSource));
963
        return result;
964

    
965
    }
966

    
967

    
968
}
(11-11/97)