Project

General

Profile

Download (37.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.DefinedTerm;
39
import eu.etaxonomy.cdm.model.common.Language;
40
import eu.etaxonomy.cdm.model.common.Marker;
41
import eu.etaxonomy.cdm.model.common.MarkerType;
42
import eu.etaxonomy.cdm.model.common.TermVocabulary;
43
import eu.etaxonomy.cdm.model.description.DescriptionBase;
44
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
45
import eu.etaxonomy.cdm.model.description.DescriptiveDataSet;
46
import eu.etaxonomy.cdm.model.description.Distribution;
47
import eu.etaxonomy.cdm.model.description.Feature;
48
import eu.etaxonomy.cdm.model.description.FeatureTree;
49
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
50
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
51
import eu.etaxonomy.cdm.model.description.TaxonDescription;
52
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
53
import eu.etaxonomy.cdm.model.description.TextData;
54
import eu.etaxonomy.cdm.model.location.NamedArea;
55
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
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.taxon.Taxon;
60
import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
61
import eu.etaxonomy.cdm.persistence.dao.common.ITermVocabularyDao;
62
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionDao;
63
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptionElementDao;
64
import eu.etaxonomy.cdm.persistence.dao.description.IDescriptiveDataSetDao;
65
import eu.etaxonomy.cdm.persistence.dao.description.IFeatureDao;
66
import eu.etaxonomy.cdm.persistence.dao.description.IFeatureNodeDao;
67
import eu.etaxonomy.cdm.persistence.dao.description.IFeatureTreeDao;
68
import eu.etaxonomy.cdm.persistence.dao.description.IStatisticalMeasurementValueDao;
69
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
70
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
71
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
72
import eu.etaxonomy.cdm.persistence.dto.TermDto;
73
import eu.etaxonomy.cdm.persistence.query.OrderHint;
74
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
75

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

    
89
    private static final Logger logger = Logger.getLogger(DescriptionServiceImpl.class);
90

    
91
    protected IDescriptionElementDao descriptionElementDao;
92
    protected IFeatureTreeDao featureTreeDao;
93
    protected IDescriptiveDataSetDao descriptiveDataSetDao;
94
    protected IFeatureNodeDao featureNodeDao;
95
    protected IFeatureDao featureDao;
96
    protected ITermVocabularyDao vocabularyDao;
97
    protected IDefinedTermDao definedTermDao;
98
    protected IStatisticalMeasurementValueDao statisticalMeasurementValueDao;
99
    protected ITaxonDao taxonDao;
100
    protected ITaxonNodeDao taxonNodeDao;
101
    protected IDescriptiveDataSetDao dataSetDao;
102

    
103
    @Autowired
104
    private IProgressMonitorService progressMonitorService;
105

    
106
    //TODO change to Interface
107
    private NaturalLanguageGenerator naturalLanguageGenerator;
108

    
109
    @Autowired
110
    protected void setFeatureTreeDao(IFeatureTreeDao featureTreeDao) {
111
        this.featureTreeDao = featureTreeDao;
112
    }
113

    
114
    @Autowired
115
    protected void setDescriptiveDataSetDao(IDescriptiveDataSetDao descriptiveDataSetDao) {
116
        this.descriptiveDataSetDao = descriptiveDataSetDao;
117
    }
118

    
119
    @Autowired
120
    protected void setFeatureNodeDao(IFeatureNodeDao featureNodeDao) {
121
        this.featureNodeDao = featureNodeDao;
122
    }
123

    
124
    @Autowired
125
    protected void setFeatureDao(IFeatureDao featureDao) {
126
        this.featureDao = featureDao;
127
    }
128

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

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

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

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

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

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

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

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

    
169
    /**
170
     *
171
     */
172
    public DescriptionServiceImpl() {
173
        logger.debug("Load DescriptionService Bean");
174
    }
175

    
176

    
177
    @Override
178
    @Transactional(readOnly = false)
179
    public void updateTitleCache(Class<? extends DescriptionBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<DescriptionBase> cacheStrategy, IProgressMonitor monitor) {
180
        if (clazz == null){
181
            clazz = DescriptionBase.class;
182
        }
183
        super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
184
    }
185

    
186

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

    
194
    @Override
195
    @Autowired
196
    protected void setDao(IDescriptionDao dao) {
197
        this.dao = dao;
198
    }
199

    
200
    @Override
201
    public long count(Class<? extends DescriptionBase> type, Boolean hasImages, Boolean hasText,Set<Feature> feature) {
202
        return dao.countDescriptions(type, hasImages, hasText, feature);
203
    }
204

    
205
    @Override
206
    public <T extends DescriptionElementBase> Pager<T> pageDescriptionElements(DescriptionBase description, Class<? extends DescriptionBase> descriptionType,
207
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
208

    
209
        List<T> results = listDescriptionElements(description, descriptionType, features, type, pageSize, pageNumber, propertyPaths);
210
        return new DefaultPagerImpl<>(pageNumber, results.size(), pageSize, results);
211
    }
212

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

    
220

    
221

    
222
    @Override
223
    public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
224
            Class<? extends DescriptionBase> descriptionType, Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber,
225
            List<String> propertyPaths) {
226

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

    
234
    }
235

    
236

    
237
    @Override
238
    @Deprecated
239
    public <T extends DescriptionElementBase> List<T> listDescriptionElements(DescriptionBase description,
240
            Set<Feature> features, Class<T> type, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
241

    
242
        return listDescriptionElements(description, null, features, type, pageSize, pageNumber, propertyPaths);
243
    }
244

    
245
    @Override
246
    public Pager<Annotation> getDescriptionElementAnnotations(DescriptionElementBase annotatedObj, MarkerType status, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
247
        long numberOfResults = descriptionElementDao.countAnnotations(annotatedObj, status);
248

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

    
254
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
255
    }
256

    
257

    
258
    @Override
259
    public Pager<Media> getMedia(DescriptionElementBase descriptionElement,	Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
260
        Integer numberOfResults = descriptionElementDao.countMedia(descriptionElement);
261

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

    
267
        return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
268
    }
269

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

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

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

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

    
291
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
292
    }
293

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

    
300

    
301
    @Override
302
    public List<Media> listTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes, Integer pageSize, Integer pageNumber, List<String> propertyPaths){
303
        return this.dao.listTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes, pageSize, pageNumber, propertyPaths);
304
    }
305

    
306
    @Override
307
    public int countTaxonDescriptionMedia(UUID taxonUuid, boolean limitToGalleries, Set<MarkerType> markerTypes){
308
        return this.dao.countTaxonDescriptionMedia(taxonUuid, limitToGalleries, markerTypes);
309
    }
310

    
311
    @Override
312
    @Deprecated
313
    public DistributionTree getOrderedDistributions(
314
            Set<TaxonDescription> taxonDescriptions,
315
            boolean subAreaPreference,
316
            boolean statusOrderPreference,
317
            Set<MarkerType> hiddenAreaMarkerTypes,
318
            Set<NamedAreaLevel> omitLevels, List<String> propertyPaths){
319

    
320
        List<Distribution> distList = new ArrayList<Distribution>();
321

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

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

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

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

    
362
        // filter distributions
363
        Collection<Distribution> filteredDistributions = DescriptionUtility.filterDistributions(distList, hiddenAreaMarkerTypes, true, statusOrderPreference, false);
364
        distList.clear();
365
        distList.addAll(filteredDistributions);
366

    
367
        return DescriptionUtility.orderDistributions(definedTermDao, omitLevels, distList, hiddenAreaMarkerTypes, null);
368
    }
369

    
370

    
371
    @Override
372
    public Pager<TaxonNameDescription> getTaxonNameDescriptions(TaxonName name, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
373
        long numberOfResults = dao.countTaxonNameDescriptions(name);
374

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

    
380
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
381
    }
382

    
383

    
384
    @Override
385
    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) {
386
        long numberOfResults = dao.countDescriptions(type, hasImages, hasText, feature);
387

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

    
394
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
395
    }
396

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

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

    
410
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
411
    }
412

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

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

    
427
        return new DefaultPagerImpl<>(pageNumber, numberOfResults, pageSize, results);
428
    }
429

    
430
    /**
431
     * FIXME Candidate for harmonization
432
     * descriptionElementService.find
433
     */
434
    @Override
435
    public DescriptionElementBase getDescriptionElementByUuid(UUID uuid) {
436
        return descriptionElementDao.findByUuid(uuid);
437
    }
438

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

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

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

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

    
480

    
481
        }
482

    
483
        return mergedObjects;
484
    }
485

    
486
    /**
487
     * FIXME Candidate for harmonization
488
     * descriptionElementService.delete
489
     */
490
    @Override
491
    public UUID deleteDescriptionElement(DescriptionElementBase descriptionElement) {
492
        return descriptionElementDao.delete(descriptionElement);
493
    }
494

    
495

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

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

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

    
523
    	Set<DescriptiveDataSet> descriptiveDataSets = description.getDescriptiveDataSets();
524
    	for (Iterator<DescriptiveDataSet> iterator = descriptiveDataSets.iterator(); iterator.hasNext();) {
525
    	    iterator.next().removeDescription(description);
526
        }
527

    
528
    	dao.delete(description);
529
    	deleteResult.addDeletedObject(description);
530
    	deleteResult.setCdmEntity(description);
531

    
532

    
533
        return deleteResult;
534
    }
535

    
536

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

    
546

    
547
    @Override
548
    public TermVocabulary<Feature> getFeatureVocabulary(UUID uuid) {
549
        return vocabularyDao.findByUuid(uuid);
550
    }
551

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

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

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

    
587

    
588
    /* (non-Javadoc)
589
     * @see eu.etaxonomy.cdm.api.service.IDescriptionService#generateNaturalLanguageDescription(eu.etaxonomy.cdm.model.description.FeatureTree, eu.etaxonomy.cdm.model.description.TaxonDescription, eu.etaxonomy.cdm.model.common.Language, java.util.List)
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() ){
715
            return result;
716
        }
717

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

    
743
                }else{
744
                    dao.saveOrUpdate(description);
745
                    result.addUpdatedObject(description);
746
                }
747
            }
748

    
749

    
750
        }
751
        dao.saveOrUpdate(targetDescription);
752
        result.addUpdatedObject(targetDescription);
753
        if (targetDescription instanceof TaxonDescription){
754
            result.addUpdatedObject(((TaxonDescription)targetDescription).getTaxon());
755
        }
756
        return result;
757
    }
758

    
759
    @Override
760
    @Transactional(readOnly = false)
761
    public UpdateResult moveDescriptionElementsToDescription(
762
            Set<UUID> descriptionElementUUIDs,
763
            UUID targetDescriptionUuid,
764
            boolean isCopy) {
765
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
766
        for(UUID deUuid : descriptionElementUUIDs) {
767
            descriptionElements.add(descriptionElementDao.load(deUuid));
768
        }
769
        DescriptionBase targetDescription = dao.load(targetDescriptionUuid);
770

    
771
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
772
    }
773

    
774
    @Override
775
    @Transactional(readOnly = false)
776
    public UpdateResult moveDescriptionElementsToDescription(
777
            Set<UUID> descriptionElementUUIDs,
778
            UUID targetTaxonUuid,
779
            String moveMessage,
780
            boolean isCopy) {
781
        Taxon targetTaxon = CdmBase.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
782
        DescriptionBase targetDescription = TaxonDescription.NewInstance(targetTaxon);
783
        targetDescription.setTitleCache(moveMessage, true);
784
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
785
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
786
        targetDescription.addAnnotation(annotation);
787

    
788
        targetDescription = dao.save(targetDescription);
789
        Set<DescriptionElementBase> descriptionElements = new HashSet<DescriptionElementBase>();
790
        for(UUID deUuid : descriptionElementUUIDs) {
791
            descriptionElements.add(descriptionElementDao.load(deUuid));
792
        }
793

    
794
        return moveDescriptionElementsToDescription(descriptionElements, targetDescription, isCopy);
795
    }
796

    
797
    @Override
798
    public Pager<TermDto> pageNamedAreasInUse(boolean includeAllParents, Integer pageSize,
799
            Integer pageNumber){
800
        List<TermDto> results = dao.listNamedAreasInUse(includeAllParents, null, null);
801
        int startIndex= pageNumber * pageSize;
802
        int toIndex = Math.min(startIndex + pageSize, results.size());
803
        List<TermDto> page = results.subList(startIndex, toIndex);
804
        return new DefaultPagerImpl<TermDto>(pageNumber, results.size(), pageSize, page);
805
    }
806

    
807

    
808
    @Override
809
    @Transactional(readOnly = false)
810
    public UpdateResult moveTaxonDescriptions(Taxon sourceTaxon, Taxon targetTaxon) {
811
        List<TaxonDescription> descriptions = new ArrayList(sourceTaxon.getDescriptions());
812
        UpdateResult result = new UpdateResult();
813
        result.addUpdatedObject(sourceTaxon);
814
        result.addUpdatedObject(targetTaxon);
815
        for(TaxonDescription description : descriptions){
816

    
817
            String moveMessage = String.format("Description moved from %s", sourceTaxon);
818
            if(description.isProtectedTitleCache()){
819
                String separator = "";
820
                if(!StringUtils.isBlank(description.getTitleCache())){
821
                    separator = " - ";
822
                }
823
                description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
824
            }
825
            Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
826
            annotation.setAnnotationType(AnnotationType.TECHNICAL());
827
            description.addAnnotation(annotation);
828
            targetTaxon.addDescription(description);
829
        }
830
        return result;
831
    }
832

    
833
    @Override
834
    @Transactional(readOnly = false)
835
    public UpdateResult moveTaxonDescriptions(UUID sourceTaxonUuid, UUID targetTaxonUuid) {
836
        Taxon sourceTaxon = HibernateProxyHelper.deproxy(taxonDao.load(sourceTaxonUuid), Taxon.class);
837
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
838
        return moveTaxonDescriptions(sourceTaxon, targetTaxon);
839

    
840
    }
841

    
842
    @Override
843
    @Transactional(readOnly = false)
844
    public UpdateResult moveTaxonDescription(UUID descriptionUuid, UUID targetTaxonUuid){
845
        UpdateResult result = new UpdateResult();
846
        TaxonDescription description = HibernateProxyHelper.deproxy(dao.load(descriptionUuid), TaxonDescription.class);
847

    
848
        Taxon sourceTaxon = description.getTaxon();
849
        String moveMessage = String.format("Description moved from %s", sourceTaxon);
850
        if(description.isProtectedTitleCache()){
851
            String separator = "";
852
            if(!StringUtils.isBlank(description.getTitleCache())){
853
                separator = " - ";
854
            }
855
            description.setTitleCache(description.getTitleCache() + separator + moveMessage, true);
856
        }
857
        Annotation annotation = Annotation.NewInstance(moveMessage, Language.getDefaultLanguage());
858
        annotation.setAnnotationType(AnnotationType.TECHNICAL());
859
        description.addAnnotation(annotation);
860
        Taxon targetTaxon = HibernateProxyHelper.deproxy(taxonDao.load(targetTaxonUuid), Taxon.class);
861
        targetTaxon.addDescription(description);
862
        result.addUpdatedObject(targetTaxon);
863
        result.addUpdatedObject(sourceTaxon);
864
       // dao.merge(description);
865
        return result;
866

    
867
    }
868

    
869

    
870
}
(16-16/103)