Project

General

Profile

Download (39.2 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.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.TaxonDistributionDTO;
29
import eu.etaxonomy.cdm.api.service.pager.Pager;
30
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
31
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
32
import eu.etaxonomy.cdm.api.utility.DescriptionUtility;
33
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
34
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
35
import eu.etaxonomy.cdm.model.common.Annotation;
36
import eu.etaxonomy.cdm.model.common.AnnotationType;
37
import eu.etaxonomy.cdm.model.common.CdmBase;
38
import eu.etaxonomy.cdm.model.common.Language;
39
import eu.etaxonomy.cdm.model.common.Marker;
40
import eu.etaxonomy.cdm.model.common.MarkerType;
41
import eu.etaxonomy.cdm.model.description.DescriptionBase;
42
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
43
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
44
import eu.etaxonomy.cdm.model.description.Distribution;
45
import eu.etaxonomy.cdm.model.description.Feature;
46
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
47
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
48
import eu.etaxonomy.cdm.model.description.TaxonDescription;
49
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
50
import eu.etaxonomy.cdm.model.description.TextData;
51
import eu.etaxonomy.cdm.model.location.NamedArea;
52
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
53
import eu.etaxonomy.cdm.model.media.Media;
54
import eu.etaxonomy.cdm.model.name.TaxonName;
55
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
56
import eu.etaxonomy.cdm.model.taxon.Taxon;
57
import eu.etaxonomy.cdm.model.term.DefinedTerm;
58
import eu.etaxonomy.cdm.model.term.FeatureTree;
59
import eu.etaxonomy.cdm.model.term.TermVocabulary;
60
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
61
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionElementDao;
62
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
63
import eu.etaxonomy.cdm.persistence.dao.description.IFeatureDao;
64
import eu.etaxonomy.cdm.persistence.dao.description.IFeatureNodeDao;
65
import eu.etaxonomy.cdm.persistence.dao.description.IFeatureTreeDao;
66
import eu.etaxonomy.cdm.persistence.dao.description.IStatisticalMeasurementValueDao;
67
import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
68
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
69
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
70
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
71
import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
72
import eu.etaxonomy.cdm.persistence.dao.term.ITermVocabularyDao;
73
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
74
import eu.etaxonomy.cdm.persistence.dto.TermDto;
75
import eu.etaxonomy.cdm.persistence.query.OrderHint;
76
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
77

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

    
91
    private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
92

    
93
    protected IDescriptionElementDao descriptionElementDao;
94
    protected IFeatureTreeDao featureTreeDao;
95
    protected IDescriptiveDataSetDao descriptiveDataSetDao;
96
    protected IFeatureNodeDao featureNodeDao;
97
    protected IFeatureDao featureDao;
98
    protected ITermVocabularyDao vocabularyDao;
99
    protected IDefinedTermDao definedTermDao;
100
    protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
101
    protected ITaxonDao taxonDao;
102
    protected ITaxonNameDao nameDao;
103
    protected IOccurrenceDao occurrenceDao;
104
    protected ITaxonNodeDao taxonNodeDao;
105
    protected IDescriptiveDataSetDao dataSetDao;
106

    
107
    @Autowired
108
    private IProgressMonitorService progressMonitorService;
109

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

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

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

    
123
    @Autowired
124
    protected void setFeatureNodeDao(IFeatureNodeDao featureNodeDao) {
125
        this.featureNodeDao = featureNodeDao;
126
    }
127

    
128
    @Autowired
129
    protected void setFeatureDao(IFeatureDao featureDao) {
130
        this.featureDao = featureDao;
131
    }
132

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

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

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

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

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

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

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

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

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

    
180

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

    
190

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

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

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

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

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

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

    
224

    
225

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

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

    
238
    }
239

    
240

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

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

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

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

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

    
261

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

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

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

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

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

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

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

    
295
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
296
    }
297

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

    
304

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

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

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

    
324
        List<Distribution> distList = new ArrayList<Distribution>();
325

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

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

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

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

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

    
371
        return DescriptionUtility.orderDistributions(definedTermDao, omitLevels, distList, hiddenAreaMarkerTypes, null);
372
    }
373

    
374

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

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

    
384
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
385
    }
386

    
387

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

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

    
398
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
399
    }
400

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

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

    
414
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
415
    }
416

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

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

    
431
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
432
    }
433

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

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

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

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

    
472
    @Override
473
    @Transactional(readOnly = false)
474
    public List<MergeResult<DescriptionBase>> mergeDescriptionElements(Collection<TaxonDistributionDTO> descriptionElements, boolean returnTransientEntity) {
475
        List<MergeResult<DescriptionBase>> mergedObjects = new ArrayList();
476
        List<Distribution> toDelete = new ArrayList<>();
477
        for(TaxonDistributionDTO obj : descriptionElements) {
478
            Iterator<TaxonDescription> iterator = obj.getDescriptionsWrapper().getDescriptions().iterator();
479
            while (iterator.hasNext()){
480
                TaxonDescription desc = iterator.next();
481
                mergedObjects.add(dao.merge(desc, returnTransientEntity));
482
            }
483

    
484

    
485
        }
486

    
487
        return mergedObjects;
488
    }
489

    
490
    /**
491
     * FIXME Candidate for harmonization
492
     * descriptionElementService.delete
493
     */
494
    @Override
495
    public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
496
        return descriptionElementDao.delete(descriptionElement);
497
    }
498

    
499

    
500
    /* (non-Javadoc)
501
     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescriptionElement(java.util.UUID)
502
     */
503
    @Override
504
    public UUID deleteDescriptionElement(UUID descriptionElementUuid) {
505
        return deleteDescriptionElement(descriptionElementDao.load(descriptionElementUuid));
506
    }
507

    
508
    @Override
509
    @Transactional(readOnly = false)
510
    public DeleteResult deleteDescription(DescriptionBase description) {
511
        DeleteResult deleteResult = new DeleteResult();
512
        description = load(description.getId(), Arrays.asList("descriptiveDataSets"));//avoid lazy init exception
513

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

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

    
532
    	dao.delete(description);
533
    	deleteResult.addDeletedObject(description);
534
    	deleteResult.setCdmEntity(description);
535

    
536

    
537
        return deleteResult;
538
    }
539

    
540

    
541
    /* (non-Javadoc)
542
     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#deleteDescription(java.util.UUID)
543
     */
544
    @Override
545
    @Transactional(readOnly = false)
546
    public DeleteResult deleteDescription(UUID descriptionUuid) {
547
        return deleteDescription(dao.load(descriptionUuid));
548
    }
549

    
550

    
551
    @Override
552
    public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
553
        return vocabularyDao.findByUuid(uuid);
554
    }
555

    
556
    @Override
557
    @Deprecated
558
    public <T extends DescriptionElementBase> List<T> getDescriptionElementsForTaxon(
559
            Taxon taxon, Set<Feature> features,
560
            Class<T> type, Integer pageSize,
561
            Integer pageNumber, List<String> propertyPaths) {
562
        return listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
563
    }
564

    
565
    @Override
566
    public <T extends DescriptionElementBase> List<T> listDescriptionElementsForTaxon(
567
            Taxon taxon, Set<Feature> features,
568
            Class<T> type, Integer pageSize,
569
            Integer pageNumber, List<String> propertyPaths) {
570
        return dao.getDescriptionElementForTaxon(taxon.getUuid(), features, type, pageSize, pageNumber, propertyPaths);
571
    }
572

    
573
    @Override
574
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElementsForTaxon(
575
            Taxon taxon, Set<Feature> features,
576
            Class<T> type, Integer pageSize,
577
            Integer pageNumber, List<String> propertyPaths) {
578
        if (logger.isDebugEnabled()){logger.debug(" get count ...");}
579
        Long count = dao.countDescriptionElementForTaxon(taxon.getUuid(), features, type);
580
        List<T> descriptionElements;
581
        if(AbstractPagerImpl.hasResultsInRange(count, pageNumber, pageSize)){ // no point checking again
582
            if (logger.isDebugEnabled()){logger.debug(" get list ...");}
583
            descriptionElements = listDescriptionElementsForTaxon(taxon, features, type, pageSize, pageNumber, propertyPaths);
584
        } else {
585
            descriptionElements = new ArrayList<T>(0);
586
        }
587
        if (logger.isDebugEnabled()){logger.debug(" service - DONE ...");}
588
        return new DefaultPagerImpl<T>(pageNumber, count, pageSize, descriptionElements);
589
    }
590

    
591
    @Override
592
    public String generateNaturalLanguageDescription(FeatureTree featureTree,
593
            TaxonDescription description, List<Language> preferredLanguages, String separator) {
594

    
595
        Language lang = preferredLanguages.size() > 0 ? preferredLanguages.get(0) : Language.DEFAULT();
596

    
597
        description = (TaxonDescription)load(description.getUuid());
598
        featureTree = featureTreeDao.load(featureTree.getUuid());
599

    
600
        StringBuilder naturalLanguageDescription = new StringBuilder();
601

    
602
        MarkerType useMarkerType = (MarkerType) definedTermDao.load(UUID.fromString("2e6e42d9-e92a-41f4-899b-03c0ac64f039"));
603
        boolean isUseDescription = false;
604
        if(!description.getMarkers().isEmpty()) {
605
            for (Marker marker: description.getMarkers()) {
606
                MarkerType markerType = marker.getMarkerType();
607
                if (markerType.equals(useMarkerType)) {
608
                    isUseDescription = true;
609
                }
610

    
611
            }
612
        }
613

    
614
        if(description.hasStructuredData() && !isUseDescription){
615

    
616

    
617
            String lastCategory = null;
618
            String categorySeparator = ". ";
619

    
620
            List<TextData> textDataList;
621
            TextData naturalLanguageDescriptionText = null;
622

    
623
            boolean useMicroFormatQuantitativeDescriptionBuilder = false;
624

    
625
            if(useMicroFormatQuantitativeDescriptionBuilder){
626

    
627
                MicroFormatQuantitativeDescriptionBuilder micro = new MicroFormatQuantitativeDescriptionBuilder();
628
                naturalLanguageGenerator.setQuantitativeDescriptionBuilder(micro);
629
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(featureTree, (description), lang);
630

    
631
            } else {
632

    
633
                naturalLanguageDescriptionText = naturalLanguageGenerator.generateSingleTextData(
634
                        featureTree,
635
                        (description),
636
                        lang);
637
            }
638

    
639
            return naturalLanguageDescriptionText.getText(lang);
640

    
641
//
642
//			boolean doItBetter = false;
643
//
644
//			for (TextData textData : textDataList.toArray(new TextData[textDataList.size()])){
645
//				if(textData.getMultilanguageText().size() > 0){
646
//
647
//					if (!textData.getFeature().equals(Feature.UNKNOWN())) {
648
//						String featureLabel = textData.getFeature().getLabel(lang);
649
//
650
//						if(doItBetter){
651
//							/*
652
//							 *  WARNING
653
//							 *  The code lines below are desinged to handle
654
//							 *  a special case where as the feature label contains
655
//							 *  hierarchical information on the features. This code
656
//							 *  exist only as a base for discussion, and is not
657
//							 *  intendet to be used in production.
658
//							 */
659
//							featureLabel = StringUtils.remove(featureLabel, '>');
660
//
661
//							String[] labelTokens = StringUtils.split(featureLabel, '<');
662
//							if(labelTokens[0].equals(lastCategory) && labelTokens.length > 1){
663
//								if(naturalLanguageDescription.length() > 0){
664
//									naturalLanguageDescription.append(separator);
665
//								}
666
//								naturalLanguageDescription.append(labelTokens[1]);
667
//							} else {
668
//								if(naturalLanguageDescription.length() > 0){
669
//									naturalLanguageDescription.append(categorySeparator);
670
//								}
671
//								naturalLanguageDescription.append(StringUtils.join(labelTokens));
672
//							}
673
//							lastCategory = labelTokens[0];
674
//							// end of demo code
675
//						} else {
676
//							if(naturalLanguageDescription.length() > 0){
677
//								naturalLanguageDescription.append(separator);
678
//							}
679
//							naturalLanguageDescription.append(textData.getFeature().getLabel(lang));
680
//						}
681
//					} else {
682
//						if(naturalLanguageDescription.length() > 0){
683
//							naturalLanguageDescription.append(separator);
684
//						}
685
//					}
686
//					String text = textData.getMultilanguageText().values().iterator().next().getText();
687
//					naturalLanguageDescription.append(text);
688
//
689
//				}
690
//			}
691

    
692
        }
693
        else if (isUseDescription) {
694
            //AT: Left Blank in case we need to generate a Natural language text string.
695
        }
696
        return naturalLanguageDescription.toString();
697
    }
698

    
699

    
700
    @Override
701
    public boolean hasStructuredData(DescriptionBase<?> description) {
702
        return load(description.getUuid()).hasStructuredData();
703
    }
704

    
705

    
706
    @Override
707
   // @Transactional(readOnly = false)
708
    public UpdateResult moveDescriptionElementsToDescription(
709
            Collection<DescriptionElementBase> descriptionElements,
710
            DescriptionBase targetDescription,
711
            boolean isCopy) {
712

    
713
        UpdateResult result = new UpdateResult();
714
        if (descriptionElements.isEmpty() || descriptionElements.iterator().next() == null){
715
            result.setAbort();
716
            return result;
717
        }
718

    
719

    
720
        if (! isCopy && descriptionElements == descriptionElements.iterator().next().getInDescription().getElements()){
721
            //if the descriptionElements collection is the elements set of a description, put it in a separate set before to avoid concurrent modification exceptions
722
            descriptionElements = new HashSet<DescriptionElementBase>(descriptionElements);
723
//			descriptionElementsTmp.addAll(descriptionElements);
724
//			descriptionElements = descriptionElementsTmp;
725
        }
726
        for (DescriptionElementBase element : descriptionElements){
727
            DescriptionBase<?> description = element.getInDescription();
728
            description = dao.load(description.getUuid());
729
            try {
730
                DescriptionElementBase newElement = (DescriptionElementBase)element.clone();
731
                targetDescription.addElement(newElement);
732
            } catch (CloneNotSupportedException e) {
733
                throw new RuntimeException ("Clone not yet implemented for class " + element.getClass().getName(), e);
734
            }
735
            if (! isCopy){
736
                description.removeElement(element);
737
                if (description.getElements().isEmpty()){
738
                   if (description instanceof TaxonDescription){
739
                       TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
740
                       if (taxDescription.getTaxon() != null){
741
                           taxDescription.getTaxon().removeDescription((TaxonDescription)description);
742
                       }
743
                   }
744
                    dao.delete(description);
745

    
746
                }//else{
747
//                    dao.saveOrUpdate(description);
748
//                    result.addUpdatedObject(description);
749
//                }
750
            }
751

    
752

    
753
        }
754
        dao.saveOrUpdate(targetDescription);
755
        result.addUpdatedObject(targetDescription);
756
        if (targetDescription instanceof TaxonDescription){
757
            result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
758
        }
759
        return result;
760
    }
761

    
762
    @Override
763
    @Transactional(readOnly = false)
764
    public UpdateResult moveDescriptionElementsToDescription(
765
            Set<UUID> descriptionElementUUIDs,
766
            UUID targetDescriptionUuid,
767
            boolean isCopy) {
768
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
769
        for(UUID deUuid : descriptionElementUUIDs) {
770
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
771
            if (element != null){
772
                descriptionElements.add(element);
773
            }
774
        }
775
        DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
776

    
777
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
778
    }
779

    
780
    @Override
781
    @Transactional(readOnly = false)
782
    public UpdateResult moveDescriptionElementsToDescription(
783
            Set<UUID> descriptionElementUUIDs,
784
            DescriptionBase targetDescription,
785
            boolean isCopy) {
786
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
787
        for(UUID deUuid : descriptionElementUUIDs) {
788
            DescriptionElementBase element = descriptionElementDao.load(deUuid);
789
            if (element != null){
790
                descriptionElements.add(element);
791
            }
792
        }
793
        DescriptionBase newTargetDescription;
794
        if (targetDescription.isPersited()){
795
            newTargetDescription = dao.load(targetDescription.getUuid());
796
        }else{
797
            if (targetDescription instanceof TaxonDescription){
798
                Taxon taxon = (Taxon)taxonDao.load(((TaxonDescription)targetDescription).getTaxon().getUuid());
799

    
800
                newTargetDescription = TaxonDescription.NewInstance(taxon, targetDescription.isImageGallery());
801

    
802
            }else if (targetDescription instanceof TaxonNameDescription){
803
                TaxonName name = nameDao.load(((TaxonNameDescription)targetDescription).getTaxonName().getUuid());
804
                newTargetDescription = TaxonNameDescription.NewInstance(name);
805
            }else {
806
                SpecimenOrObservationBase specimen = occurrenceDao.load(((SpecimenDescription)targetDescription).getDescribedSpecimenOrObservation().getUuid());
807
                newTargetDescription = SpecimenDescription.NewInstance(specimen);
808
            }
809

    
810
            newTargetDescription.addSources(targetDescription.getSources());
811
            newTargetDescription.setTitleCache(targetDescription.getTitleCache(), targetDescription.isProtectedTitleCache());
812

    
813
        }
814
        return moveDescriptionElementsToDescription(descriptionElements, newTargetDescription, isCopy);
815
    }
816

    
817

    
818
    @Override
819
    @Transactional(readOnly = false)
820
    public UpdateResult moveDescriptionElementsToDescription(
821
            Set<UUID> descriptionElementUUIDs,
822
            UUID targetTaxonUuid,
823
            String moveMessage,
824
            boolean isCopy) {
825
        Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
826
        DescriptionBase targetDescription = TaxonDescription.NewInstance(targetTaxon);
827
        targetDescription.setTitleCache(moveMessage, true);
828
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
829
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
830
        targetDescription.addAnnotation(annotation);
831

    
832
        targetDescription = dao.save(targetDescription);
833
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
834
        for(UUID deUuid : descriptionElementUUIDs) {
835
            descriptionElements.add(descriptionElementDao.load(deUuid));
836
        }
837

    
838
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
839
    }
840

    
841
    @Override
842
    public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
843
            Integer pageNumber){
844
        List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
845
        int startIndex= pageNumber * pageSize;
846
        int toIndex = Math.min(startIndex + pageSize, results.size());
847
        List<TermDto> page = results.subList(startIndex, toIndex);
848
        return new DefaultPagerImpl<TermDto>(pageNumber, results.size(), pageSize, page);
849
    }
850

    
851

    
852
    @Override
853
    @Transactional(readOnly = false)
854
    public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon) {
855
        List<TaxonDescription> descriptions = new ArrayList(sourceTaxon.getDescriptions());
856
        UpdateResult result = new UpdateResult();
857
        result.addUpdatedObject(sourceTaxon);
858
        result.addUpdatedObject(targetTaxon);
859
        for(TaxonDescription description : descriptions){
860

    
861
            String moveMessage = String.format("Description moved from %s", sourceTaxon);
862
            if(description.isProtectedTitleCache()){
863
                String separator = "";
864
                if(!StringUtils.isBlank(description.getTitleCache())){
865
                    separator = " - ";
866
                }
867
                description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
868
            }
869
            Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
870
            annotation.setAnnotationType(AnnotationType.TECHNICAL());
871
            description.addAnnotation(annotation);
872
            targetTaxon.addDescription(description);
873
        }
874
        return result;
875
    }
876

    
877
    @Override
878
    @Transactional(readOnly = false)
879
    public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid) {
880
        Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
881
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
882
        return moveTaxonDescriptions(sourceTaxon, targetTaxon);
883

    
884
    }
885

    
886
    @Override
887
    @Transactional(readOnly = false)
888
    public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid){
889
        UpdateResult result = new UpdateResult();
890
        TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
891

    
892
        Taxon sourceTaxon = description.getTaxon();
893
        String moveMessage = String.format("Description moved from %s", sourceTaxon);
894
        if(description.isProtectedTitleCache()){
895
            String separator = "";
896
            if(!StringUtils.isBlank(description.getTitleCache())){
897
                separator = " - ";
898
            }
899
            description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
900
        }
901
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
902
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
903
        description.addAnnotation(annotation);
904
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
905
        targetTaxon.addDescription(description);
906
        result.addUpdatedObject(targetTaxon);
907
        result.addUpdatedObject(sourceTaxon);
908
       // dao.merge(description);
909
        return result;
910

    
911
    }
912

    
913

    
914
}
(16-16/103)