Project

General

Profile

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

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

    
13
import java.util.ArrayList;
14
import java.util.Comparator;
15
import java.util.HashSet;
16
import java.util.List;
17
import java.util.Set;
18
import java.util.UUID;
19

    
20
import org.apache.log4j.Logger;
21
import org.springframework.beans.factory.annotation.Autowired;
22
import org.springframework.stereotype.Service;
23
import org.springframework.transaction.annotation.Propagation;
24
import org.springframework.transaction.annotation.Transactional;
25

    
26
import eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator;
27
import eu.etaxonomy.cdm.api.service.config.MatchingTaxonConfigurator;
28
import eu.etaxonomy.cdm.api.service.pager.Pager;
29
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
30
import eu.etaxonomy.cdm.common.IProgressMonitor;
31
import eu.etaxonomy.cdm.model.common.CdmBase;
32
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
33
import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
34
import eu.etaxonomy.cdm.model.common.RelationshipBase;
35
import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
36
import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;
37
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
38
import eu.etaxonomy.cdm.model.description.TaxonDescription;
39
import eu.etaxonomy.cdm.model.media.Media;
40
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
41
import eu.etaxonomy.cdm.model.media.MediaUtils;
42
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
43
import eu.etaxonomy.cdm.model.name.Rank;
44
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
45
import eu.etaxonomy.cdm.model.reference.Reference;
46
import eu.etaxonomy.cdm.model.taxon.Classification;
47
import eu.etaxonomy.cdm.model.taxon.Synonym;
48
import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
49
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
50
import eu.etaxonomy.cdm.model.taxon.Taxon;
51
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
52
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
53
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
54
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
55
import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao;
56
import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
57
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
58
import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;
59
import eu.etaxonomy.cdm.persistence.query.MatchMode;
60
import eu.etaxonomy.cdm.persistence.query.OrderHint;
61
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
62

    
63

    
64
/**
65
 * @author a.kohlbecker
66
 * @date 10.09.2010
67
 *
68
 */
69
@Service
70
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
71
public class TaxonServiceImpl extends IdentifiableServiceBase<TaxonBase,ITaxonDao> implements ITaxonService{
72
    private static final Logger logger = Logger.getLogger(TaxonServiceImpl.class);
73

    
74
	@Autowired
75
	private ITaxonNameDao nameDao;
76

    
77
	@Autowired
78
	private IOrderedTermVocabularyDao orderedVocabularyDao;
79

    
80
	@Autowired
81
	private INameService nameService;
82
	
83
	/**
84
	 * Constructor
85
	 */
86
	public TaxonServiceImpl(){
87
		if (logger.isDebugEnabled()) { logger.debug("Load TaxonService Bean"); }
88
	}
89

    
90
    /**
91
     * FIXME Candidate for harmonization
92
     * rename searchByName ?
93
     */
94
    public List<TaxonBase> searchTaxaByName(String name, Reference sec) {
95
        return dao.getTaxaByName(name, sec);
96
    }
97

    
98
    /**
99
     * FIXME Candidate for harmonization
100
     * list(Synonym.class, ...)
101
     *  (non-Javadoc)
102
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
103
     */
104
    public List<Synonym> getAllSynonyms(int limit, int start) {
105
        return dao.getAllSynonyms(limit, start);
106
    }
107

    
108
    /**
109
     * FIXME Candidate for harmonization
110
     * list(Taxon.class, ...)
111
     *  (non-Javadoc)
112
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
113
     */
114
    public List<Taxon> getAllTaxa(int limit, int start) {
115
        return dao.getAllTaxa(limit, start);
116
    }
117

    
118
    /**
119
     * FIXME Candidate for harmonization
120
     * merge with getRootTaxa(Reference sec, ..., ...)
121
     *  (non-Javadoc)
122
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
123
     */
124
    public List<Taxon> getRootTaxa(Reference sec, CdmFetch cdmFetch, boolean onlyWithChildren) {
125
        if (cdmFetch == null){
126
            cdmFetch = CdmFetch.NO_FETCH();
127
        }
128
        return dao.getRootTaxa(sec, cdmFetch, onlyWithChildren, false);
129
    }
130

    
131

    
132
    /* (non-Javadoc)
133
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
134
     */
135
    public List<Taxon> getRootTaxa(Rank rank, Reference sec, boolean onlyWithChildren,boolean withMisapplications, List<String> propertyPaths) {
136
        return dao.getRootTaxa(rank, sec, null, onlyWithChildren, withMisapplications, propertyPaths);
137
    }
138

    
139
    /* (non-Javadoc)
140
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
141
     */
142
    public List<RelationshipBase> getAllRelationships(int limit, int start){
143
        return dao.getAllRelationships(limit, start);
144
    }
145

    
146
    /**
147
     * FIXME Candidate for harmonization
148
     * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
149
     */
150
    @Deprecated
151
    public OrderedTermVocabulary<TaxonRelationshipType> getTaxonRelationshipTypeVocabulary() {
152

    
153
        String taxonRelTypeVocabularyId = "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
154
        UUID uuid = UUID.fromString(taxonRelTypeVocabularyId);
155
        OrderedTermVocabulary<TaxonRelationshipType> taxonRelTypeVocabulary =
156
            (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
157
        return taxonRelTypeVocabulary;
158
    }
159

    
160
    
161
    
162
	/*
163
	 * (non-Javadoc)
164
	 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
165
	 */
166
	@Transactional(readOnly = false)
167
	public void swapSynonymAndAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon){
168
		
169
		TaxonNameBase<?,?> synonymName = synonym.getName();
170
		synonymName.removeTaxonBase(synonym);
171
		TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();
172
		taxonName.removeTaxonBase(acceptedTaxon);
173
		
174
		synonym.setName(taxonName);
175
		acceptedTaxon.setName(synonymName);
176
		
177
		// the accepted taxon needs a new uuid because the concept has changed
178
		// FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
179
		//acceptedTaxon.setUuid(UUID.randomUUID());
180
	}
181

    
182
	
183
	/* (non-Javadoc)
184
	 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
185
	 */
186
	//TODO correct delete handling still needs to be implemented / checked
187
	@Override
188
	@Transactional(readOnly = false)
189
	public Taxon changeSynonymToAcceptedTaxon(Synonym synonym, Taxon acceptedTaxon, boolean deleteSynonym, boolean copyCitationInfo, Reference citation, String microCitation) throws IllegalArgumentException{
190
		
191
		TaxonNameBase<?,?> acceptedName = acceptedTaxon.getName();
192
		TaxonNameBase<?,?> synonymName = synonym.getName();
193
		HomotypicalGroup synonymHomotypicGroup = synonymName.getHomotypicalGroup();
194
		
195
		//check synonym is not homotypic
196
		if (acceptedName.getHomotypicalGroup().equals(synonymHomotypicGroup)){
197
			String message = "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
198
			throw new IllegalArgumentException(message);
199
		}
200
		
201
		Taxon newAcceptedTaxon = Taxon.NewInstance(synonymName, acceptedTaxon.getSec());
202
		
203
		SynonymRelationshipType relTypeForGroup = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
204
		List<Synonym> heteroSynonyms = acceptedTaxon.getSynonymsInGroup(synonymHomotypicGroup);
205
		
206
		for (Synonym heteroSynonym : heteroSynonyms){
207
			if (synonym.equals(heteroSynonym)){
208
				acceptedTaxon.removeSynonym(heteroSynonym, false);
209
			}else{
210
				//move synonyms in same homotypic group to new accepted taxon
211
				heteroSynonym.replaceAcceptedTaxon(newAcceptedTaxon, relTypeForGroup, copyCitationInfo, citation, microCitation);
212
			}
213
		}
214

    
215
		//synonym.getName().removeTaxonBase(synonym);
216
		//TODO correct delete handling still needs to be implemented / checked
217
		if (deleteSynonym){
218
//			deleteSynonym(synonym, taxon, false);
219
			try {
220
				this.dao.flush();
221
				this.delete(synonym);
222
				
223
			} catch (Exception e) {
224
				logger.info("Can't delete old synonym from database");
225
			}
226
		}
227
		
228
		return newAcceptedTaxon;
229
	}
230
	
231
	
232
	public Taxon changeSynonymToRelatedTaxon(Synonym synonym, Taxon toTaxon, TaxonRelationshipType taxonRelationshipType, Reference citation, String microcitation){
233
		
234
		// Get name from synonym
235
		TaxonNameBase<?, ?> synonymName = synonym.getName();
236
		
237
		// remove synonym from taxon
238
		toTaxon.removeSynonym(synonym);
239
		
240
		// Create a taxon with synonym name
241
		Taxon fromTaxon = Taxon.NewInstance(synonymName, null);
242
		
243
		// Add taxon relation 
244
		fromTaxon.addTaxonRelation(toTaxon, taxonRelationshipType, citation, microcitation);
245
				
246
		// since we are swapping names, we have to detach the name from the synonym completely. 
247
		// Otherwise the synonym will still be in the list of typified names.
248
		synonym.getName().removeTaxonBase(synonym);
249
		
250
		return fromTaxon;
251
	}
252
	
253

    
254
    /* (non-Javadoc)
255
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeHomotypicalGroupOfSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.name.HomotypicalGroup, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
256
     */
257
    @Transactional(readOnly = false)
258
    @Override
259
    public void changeHomotypicalGroupOfSynonym(Synonym synonym, HomotypicalGroup newHomotypicalGroup, Taxon targetTaxon,
260
                        boolean removeFromOtherTaxa, boolean setBasionymRelationIfApplicable){
261
        // Get synonym name
262
        TaxonNameBase synonymName = synonym.getName();
263
        HomotypicalGroup oldHomotypicalGroup = synonymName.getHomotypicalGroup();
264

    
265

    
266
        // Switch groups
267
        oldHomotypicalGroup.removeTypifiedName(synonymName);
268
        newHomotypicalGroup.addTypifiedName(synonymName);
269

    
270
        //remove existing basionym relationships
271
        synonymName.removeBasionyms();
272

    
273
        //add basionym relationship
274
        if (setBasionymRelationIfApplicable){
275
            Set<TaxonNameBase> basionyms = newHomotypicalGroup.getBasionyms();
276
            for (TaxonNameBase basionym : basionyms){
277
                synonymName.addBasionym(basionym);
278
            }
279
        }
280

    
281
        //set synonym relationship correctly
282
//			SynonymRelationship relToTaxon = null;
283
        boolean relToTargetTaxonExists = false;
284
        Set<SynonymRelationship> existingRelations = synonym.getSynonymRelations();
285
        for (SynonymRelationship rel : existingRelations){
286
            Taxon acceptedTaxon = rel.getAcceptedTaxon();
287
            boolean isTargetTaxon = acceptedTaxon != null && acceptedTaxon.equals(targetTaxon);
288
            HomotypicalGroup acceptedGroup = acceptedTaxon.getHomotypicGroup();
289
            boolean isHomotypicToTaxon = acceptedGroup.equals(newHomotypicalGroup);
290
            SynonymRelationshipType newRelationType = isHomotypicToTaxon? SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
291
            rel.setType(newRelationType);
292
            //TODO handle citation and microCitation
293

    
294
            if (isTargetTaxon){
295
                relToTargetTaxonExists = true;
296
            }else{
297
                if (removeFromOtherTaxa){
298
                    acceptedTaxon.removeSynonym(synonym, false);
299
                }else{
300
                    //do nothing
301
                }
302
            }
303
        }
304
        if (targetTaxon != null &&  ! relToTargetTaxonExists ){
305
            Taxon acceptedTaxon = targetTaxon;
306
            HomotypicalGroup acceptedGroup = acceptedTaxon.getHomotypicGroup();
307
            boolean isHomotypicToTaxon = acceptedGroup.equals(newHomotypicalGroup);
308
            SynonymRelationshipType relType = isHomotypicToTaxon? SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF();
309
            //TODO handle citation and microCitation
310
            Reference citation = null;
311
            String microCitation = null;
312
            acceptedTaxon.addSynonym(synonym, relType, citation, microCitation);
313
        }
314

    
315
    }
316

    
317

    
318
    /* (non-Javadoc)
319
     * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
320
     */
321
    @Override
322
    public void updateTitleCache(Class<? extends TaxonBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<TaxonBase> cacheStrategy, IProgressMonitor monitor) {
323
        if (clazz == null){
324
            clazz = TaxonBase.class;
325
        }
326
        super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
327
    }
328

    
329
    @Autowired
330
    protected void setDao(ITaxonDao dao) {
331
        this.dao = dao;
332
    }
333

    
334
    /* (non-Javadoc)
335
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)
336
     */
337
    public Pager<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String uninomial,	String infragenericEpithet, String specificEpithet,	String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {
338
        Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);
339

    
340
        List<TaxonBase> results = new ArrayList<TaxonBase>();
341
        if(numberOfResults > 0) { // no point checking again
342
            results = dao.findTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber);
343
        }
344

    
345
        return new DefaultPagerImpl<TaxonBase>(pageNumber, numberOfResults, pageSize, results);
346
    }
347

    
348
    /* (non-Javadoc)
349
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)
350
     */
351
    public List<TaxonBase> listTaxaByName(Class<? extends TaxonBase> clazz, String uninomial,	String infragenericEpithet, String specificEpithet,	String infraspecificEpithet, Rank rank, Integer pageSize,Integer pageNumber) {
352
        Integer numberOfResults = dao.countTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank);
353

    
354
        List<TaxonBase> results = new ArrayList<TaxonBase>();
355
        if(numberOfResults > 0) { // no point checking again
356
            results = dao.findTaxaByName(clazz, uninomial, infragenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber);
357
        }
358

    
359
        return results;
360
    }
361

    
362
    /* (non-Javadoc)
363
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
364
     */
365
    public List<TaxonRelationship> listToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
366
        Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);
367

    
368
        List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
369
        if(numberOfResults > 0) { // no point checking again
370
            results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedTo);
371
        }
372
        return results;
373
    }
374

    
375
    /* (non-Javadoc)
376
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
377
     */
378
    public Pager<TaxonRelationship> pageToTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
379
        Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedTo);
380

    
381
        List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
382
        if(numberOfResults > 0) { // no point checking again
383
            results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedTo);
384
        }
385
        return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);
386
    }
387

    
388
    /* (non-Javadoc)
389
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
390
     */
391
    public List<TaxonRelationship> listFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths){
392
        Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);
393

    
394
        List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
395
        if(numberOfResults > 0) { // no point checking again
396
            results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedFrom);
397
        }
398
        return results;
399
    }
400

    
401
    /* (non-Javadoc)
402
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
403
     */
404
    public Pager<TaxonRelationship> pageFromTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
405
        Integer numberOfResults = dao.countTaxonRelationships(taxon, type, TaxonRelationship.Direction.relatedFrom);
406

    
407
        List<TaxonRelationship> results = new ArrayList<TaxonRelationship>();
408
        if(numberOfResults > 0) { // no point checking again
409
            results = dao.getTaxonRelationships(taxon, type, pageSize, pageNumber, orderHints, propertyPaths, TaxonRelationship.Direction.relatedFrom);
410
        }
411
        return new DefaultPagerImpl<TaxonRelationship>(pageNumber, numberOfResults, pageSize, results);
412
    }
413

    
414
    /* (non-Javadoc)
415
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
416
     */
417
    public Pager<SynonymRelationship> getSynonyms(Taxon taxon,	SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
418
        Integer numberOfResults = dao.countSynonyms(taxon, type);
419

    
420
        List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
421
        if(numberOfResults > 0) { // no point checking again
422
            results = dao.getSynonyms(taxon, type, pageSize, pageNumber, orderHints, propertyPaths);
423
        }
424

    
425
        return new DefaultPagerImpl<SynonymRelationship>(pageNumber, numberOfResults, pageSize, results);
426
    }
427

    
428
    /* (non-Javadoc)
429
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
430
     */
431
    public Pager<SynonymRelationship> getSynonyms(Synonym synonym,	SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
432
        Integer numberOfResults = dao.countSynonyms(synonym, type);
433
		
434
		List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
435
		if(numberOfResults > 0) { // no point checking again
436
		    results = dao.getSynonyms(synonym, type, pageSize, pageNumber, orderHints, propertyPaths);
437
		}
438

    
439
        return new DefaultPagerImpl<SynonymRelationship>(pageNumber, numberOfResults, pageSize, results);
440
    }
441

    
442
	/* (non-Javadoc)
443
	 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
444
	 */
445
	public List<Synonym> getHomotypicSynonymsByHomotypicGroup(Taxon taxon, List<String> propertyPaths){
446
		Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);
447
		return t.getHomotypicSynonymsByHomotypicGroup();
448
	}
449
	
450
	/* (non-Javadoc)
451
	 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
452
	 */
453
	public List<List<Synonym>> getHeterotypicSynonymyGroups(Taxon taxon, List<String> propertyPaths){
454
		Taxon t = (Taxon)dao.load(taxon.getUuid(), propertyPaths);
455
		List<HomotypicalGroup> homotypicalGroups = t.getHeterotypicSynonymyGroups();
456
		List<List<Synonym>> heterotypicSynonymyGroups = new ArrayList<List<Synonym>>(homotypicalGroups.size());
457
		for(HomotypicalGroup homotypicalGroup : homotypicalGroups){
458
			heterotypicSynonymyGroups.add(t.getSynonymsInGroup(homotypicalGroup));
459
		}
460
		return heterotypicSynonymyGroups;
461
	}
462

    
463
	public List<UuidAndTitleCache<TaxonBase>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator){
464
		
465
		List<UuidAndTitleCache<TaxonBase>> result = new ArrayList<UuidAndTitleCache<TaxonBase>>();
466
		Class<? extends TaxonBase> clazz = null;
467
		if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
468
			clazz = TaxonBase.class;
469
			//propertyPath.addAll(configurator.getTaxonPropertyPath());
470
			//propertyPath.addAll(configurator.getSynonymPropertyPath());
471
		} else if(configurator.isDoTaxa()) {
472
			clazz = Taxon.class;
473
			//propertyPath = configurator.getTaxonPropertyPath();
474
		} else if (configurator.isDoSynonyms()) {
475
			clazz = Synonym.class;
476
			//propertyPath = configurator.getSynonymPropertyPath();
477
		}
478
		
479
		
480
		result = dao.getTaxaByNameForEditor(clazz, configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());
481
		return result;
482
	}
483

    
484
	/* (non-Javadoc)
485
	 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
486
	 */
487
	public Pager<IdentifiableEntity> findTaxaAndNames(ITaxonServiceConfigurator configurator) {
488
		
489
		List<IdentifiableEntity> results = new ArrayList<IdentifiableEntity>();
490
		int numberOfResults = 0; // overall number of results (as opposed to number of results per page)
491
		List<TaxonBase> taxa = null; 
492

    
493
        // Taxa and synonyms
494
        long numberTaxaResults = 0L;
495

    
496
        Class<? extends TaxonBase> clazz = null;
497
        List<String> propertyPath = new ArrayList<String>();
498
        if(configurator.getTaxonPropertyPath() != null){
499
            propertyPath.addAll(configurator.getTaxonPropertyPath());
500
        }
501
        if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
502
            clazz = TaxonBase.class;
503
            //propertyPath.addAll(configurator.getTaxonPropertyPath());
504
            //propertyPath.addAll(configurator.getSynonymPropertyPath());
505
        } else if(configurator.isDoTaxa()) {
506
            clazz = Taxon.class;
507
            //propertyPath = configurator.getTaxonPropertyPath();
508
        } else if (configurator.isDoSynonyms()) {
509
            clazz = Synonym.class;
510
            //propertyPath = configurator.getSynonymPropertyPath();
511
        }
512

    
513
        if(clazz != null){
514
            if(configurator.getPageSize() != null){ // no point counting if we need all anyway
515
                numberTaxaResults =
516
                    dao.countTaxaByName(clazz,
517
                        configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(),
518
                        configurator.getNamedAreas());
519
            }
520

    
521
            if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){ // no point checking again if less results
522
                taxa = dao.getTaxaByName(clazz,
523
                    configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(),
524
                    configurator.getNamedAreas(), configurator.getPageSize(),
525
                    configurator.getPageNumber(), propertyPath);
526
            }
527
        }
528

    
529
        if (logger.isDebugEnabled()) { logger.debug(numberTaxaResults + " matching taxa counted"); }
530

    
531
        if(taxa != null){
532
            results.addAll(taxa);
533
        }
534

    
535
        numberOfResults += numberTaxaResults;
536

    
537
        // Names without taxa
538
        if (configurator.isDoNamesWithoutTaxa()) {
539
            int numberNameResults = 0;
540

    
541
            List<? extends TaxonNameBase<?,?>> names =
542
                nameDao.findByName(configurator.getTitleSearchStringSqlized(), configurator.getMatchMode(),
543
                        configurator.getPageSize(), configurator.getPageNumber(), null, configurator.getTaxonNamePropertyPath());
544
            if (logger.isDebugEnabled()) { logger.debug(names.size() + " matching name(s) found"); }
545
            if (names.size() > 0) {
546
                for (TaxonNameBase<?,?> taxonName : names) {
547
                    if (taxonName.getTaxonBases().size() == 0) {
548
                        results.add(taxonName);
549
                        numberNameResults++;
550
                    }
551
                }
552
                if (logger.isDebugEnabled()) { logger.debug(numberNameResults + " matching name(s) without taxa found"); }
553
                numberOfResults += numberNameResults;
554
            }
555
        }
556

    
557
        // Taxa from common names
558

    
559
        if (configurator.isDoTaxaByCommonNames()) {
560
            taxa = null;
561
            numberTaxaResults = 0;
562
            if(configurator.getPageSize() != null){// no point counting if we need all anyway
563
                numberTaxaResults = dao.countTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas());
564
            }
565
            if(configurator.getPageSize() == null || numberTaxaResults > configurator.getPageSize() * configurator.getPageNumber()){
566
                taxa = dao.getTaxaByCommonName(configurator.getTitleSearchStringSqlized(), configurator.getClassification(), configurator.getMatchMode(), configurator.getNamedAreas(), configurator.getPageSize(), configurator.getPageNumber(), configurator.getTaxonPropertyPath());
567
            }
568
            if(taxa != null){
569
                results.addAll(taxa);
570
            }
571
            numberOfResults += numberTaxaResults;
572

    
573
        }
574

    
575
       return new DefaultPagerImpl<IdentifiableEntity>
576
            (configurator.getPageNumber(), numberOfResults, configurator.getPageSize(), results);
577
    }
578

    
579
    public List<UuidAndTitleCache<TaxonBase>> getTaxonUuidAndTitleCache(){
580
        return dao.getUuidAndTitleCache();
581
    }
582

    
583
    /* (non-Javadoc)
584
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
585
     */
586
    public List<MediaRepresentation> getAllMedia(Taxon taxon, int size, int height, int widthOrDuration, String[] mimeTypes){
587
        List<MediaRepresentation> medRep = new ArrayList<MediaRepresentation>();
588
        taxon = (Taxon)dao.load(taxon.getUuid());
589
        Set<TaxonDescription> descriptions = taxon.getDescriptions();
590
        for (TaxonDescription taxDesc: descriptions){
591
            Set<DescriptionElementBase> elements = taxDesc.getElements();
592
            for (DescriptionElementBase descElem: elements){
593
                for(Media media : descElem.getMedia()){
594

    
595
                    //find the best matching representation
596
                    medRep.add(MediaUtils.findBestMatchingRepresentation(media, null, size, height, widthOrDuration, mimeTypes));
597

    
598
                }
599
            }
600
        }
601
        return medRep;
602
    }
603

    
604
    /* (non-Javadoc)
605
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
606
     */
607
    public List<TaxonBase> findTaxaByID(Set<Integer> listOfIDs) {
608
        return this.dao.findById(listOfIDs);
609
    }
610

    
611
    /* (non-Javadoc)
612
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
613
     */
614
    public int countAllRelationships() {
615
        return this.dao.countAllRelationships();
616
    }
617

    
618
    /* (non-Javadoc)
619
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#createAllInferredSynonyms(eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.model.taxon.Taxon)
620
     */
621
    public List<Synonym> createAllInferredSynonyms(Classification tree,
622
            Taxon taxon) {
623

    
624
        return this.dao.createAllInferredSynonyms(taxon, tree);
625
    }
626

    
627
    /* (non-Javadoc)
628
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#createInferredSynonyms(eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType)
629
     */
630
    public List<Synonym> createInferredSynonyms(Classification tree, Taxon taxon, SynonymRelationshipType type) {
631

    
632
        return this.dao.createInferredSynonyms(taxon, tree, type);
633
    }
634

    
635
    /* (non-Javadoc)
636
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
637
     */
638
    public List<TaxonNameBase> findIdenticalTaxonNames(List<String> propertyPath) {
639

    
640
        return this.dao.findIdenticalTaxonNames(propertyPath);
641
    }
642

    
643

    
644
	/* (non-Javadoc)
645
	 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.Synonym, boolean)
646
	 */
647
	//TODO move to dao??
648
	@Transactional(readOnly = false)
649
	@Override
650
	public void deleteSynonym(Synonym synonym, Taxon taxon, boolean removeNameIfPossible) {
651
		//remove synonymRelationship
652
		Set<Taxon> taxonSet = new HashSet<Taxon>();
653
		if (taxon != null){
654
			taxonSet.add(taxon);
655
		}else{
656
			taxonSet.addAll(synonym.getAcceptedTaxa());
657
		}
658
		Set<SynonymRelationship> synRels = synonym.getSynonymRelations();
659
		for (Taxon taxon2 : taxonSet){
660
			dao.deleteSynonymRelationships(synonym, taxon2);
661
		}
662
		
663
		//TODO remove name from homotypical group?
664
		
665
		//remove synonym (if necessary)
666
		if (synonym.getSynonymRelations().isEmpty()){
667
			dao.delete(synonym);
668
		}
669
		
670
		if (removeNameIfPossible){
671
			TaxonNameBase name = synonym.getName();
672
			nameService.delete(name);
673
			//check is used
674
				//name relationship
675
				//concept
676
				//descriptionElementSource
677
				//
678
		}
679
	}
680
	
681
	
682
    /* (non-Javadoc)
683
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
684
     */
685
    public List<TaxonNameBase> findIdenticalTaxonNameIds(List<String> propertyPath) {
686

    
687
        return this.dao.findIdenticalNamesNew(propertyPath);
688
    }
689

    
690
    /* (non-Javadoc)
691
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
692
     */
693
    public String getPhylumName(TaxonNameBase name){
694
        return this.dao.getPhylumName(name);
695
    }
696

    
697
	/* (non-Javadoc)
698
	 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
699
	 */
700
	public long deleteSynonymRelationships(Synonym syn) {
701
		return dao.deleteSynonymRelationships(syn, null);
702
	}
703

    
704

    
705
    /* (non-Javadoc)
706
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#listSynonymRelationships(eu.etaxonomy.cdm.model.taxon.TaxonBase, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List, eu.etaxonomy.cdm.model.common.RelationshipBase.Direction)
707
     */
708
    public List<SynonymRelationship> listSynonymRelationships(
709
            TaxonBase taxonBase, SynonymRelationshipType type, Integer pageSize, Integer pageNumber,
710
            List<OrderHint> orderHints, List<String> propertyPaths, Direction direction) {
711
        Integer numberOfResults = dao.countSynonymRelationships(taxonBase, type, direction);
712

    
713
        List<SynonymRelationship> results = new ArrayList<SynonymRelationship>();
714
        if(numberOfResults > 0) { // no point checking again
715
            results = dao.getSynonymRelationships(taxonBase, type, pageSize, pageNumber, orderHints, propertyPaths, direction);
716
        }
717
        return results;
718
    }
719

    
720
    /* (non-Javadoc)
721
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
722
     */
723
    @Override
724
    public Taxon findBestMatchingTaxon(String taxonName) {
725
        MatchingTaxonConfigurator config = MatchingTaxonConfigurator.NewInstance();
726
        config.setTaxonNameTitle(taxonName);
727
        return findBestMatchingTaxon(config);
728
    }
729

    
730

    
731

    
732
    @Override
733
    public Taxon findBestMatchingTaxon(MatchingTaxonConfigurator config) {
734

    
735
        Taxon bestCandidate = null;
736
        try{
737
            // 1. search for acceptet taxa
738
            List<TaxonBase> taxonList = dao.findByNameTitleCache(Taxon.class, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
739
            boolean bestCandidateMatchesSecUuid = false;
740
            boolean bestCandidateIsInClassification = false;
741
            int countEqualCandidates = 0;
742
            for(TaxonBase taxonBaseCandidate : taxonList){
743
                if(taxonBaseCandidate instanceof Taxon){
744
                    Taxon newCanditate = CdmBase.deproxy(taxonBaseCandidate, Taxon.class);
745
                    boolean newCandidateMatchesSecUuid = isMatchesSecUuid(newCanditate, config);
746
                    if (! newCandidateMatchesSecUuid && config.isOnlyMatchingSecUuid() ){
747
                        continue;
748
                    }else if(newCandidateMatchesSecUuid && ! bestCandidateMatchesSecUuid){
749
                        bestCandidate = newCanditate;
750
                        countEqualCandidates = 1;
751
                        bestCandidateMatchesSecUuid = true;
752
                        continue;
753
                    }
754

    
755
                    boolean newCandidateInClassification = isInClassification(newCanditate, config);
756
                    if (! newCandidateInClassification && config.isOnlyMatchingClassificationUuid()){
757
                        continue;
758
                    }else if (newCandidateInClassification && ! bestCandidateIsInClassification){
759
                        bestCandidate = newCanditate;
760
                        countEqualCandidates = 1;
761
                        bestCandidateIsInClassification = true;
762
                        continue;
763
                    }
764
                    if (bestCandidate == null){
765
                        bestCandidate = newCanditate;
766
                        countEqualCandidates = 1;
767
                        continue;
768
                    }
769

    
770
                }else{  //not Taxon.class
771
                    continue;
772
                }
773
                countEqualCandidates++;
774

    
775
            }
776
            if (bestCandidate != null){
777
                if(countEqualCandidates > 1){
778
                    logger.info(countEqualCandidates + " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate.getTitleCache());
779
                    return bestCandidate;
780
                } else {
781
                    logger.info("using accepted Taxon: " + bestCandidate.getTitleCache());
782
                    return bestCandidate;
783
                }
784
            }
785

    
786

    
787
            // 2. search for synonyms
788
            if (config.isIncludeSynonyms()){
789
                List<TaxonBase> synonymList = dao.findByNameTitleCache(Synonym.class, config.getTaxonNameTitle(), null, MatchMode.EXACT, null, 0, null, null);
790
                for(TaxonBase taxonBase : synonymList){
791
                    if(taxonBase instanceof Synonym){
792
                        Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);
793
                        Set<Taxon> acceptetdCandidates = synonym.getAcceptedTaxa();
794
                        if(!acceptetdCandidates.isEmpty()){
795
                            bestCandidate = acceptetdCandidates.iterator().next();
796
                            if(acceptetdCandidates.size() == 1){
797
                                logger.info(acceptetdCandidates.size() + " Accepted taxa found for synonym " + taxonBase.getTitleCache() + ", using first one: " + bestCandidate.getTitleCache());
798
                                return bestCandidate;
799
                            } else {
800
                                logger.info("using accepted Taxon " +  bestCandidate.getTitleCache() + "for synonym " + taxonBase.getTitleCache());
801
                                return bestCandidate;
802
                            }
803
                            //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
804
                        }
805
                    }
806
                }
807
            }
808

    
809
        } catch (Exception e){
810
            logger.error(e);
811
        }
812

    
813
        return bestCandidate;
814
    }
815

    
816
    private boolean isInClassification(Taxon taxon, MatchingTaxonConfigurator config) {
817
        UUID configClassificationUuid = config.getClassificationUuid();
818
        if (configClassificationUuid == null){
819
            return false;
820
        }
821
        for (TaxonNode node : taxon.getTaxonNodes()){
822
            UUID classUuid = node.getClassification().getUuid();
823
            if (configClassificationUuid.equals(classUuid)){
824
                return true;
825
            }
826
        }
827
        return false;
828
    }
829

    
830
    private boolean isMatchesSecUuid(Taxon taxon, MatchingTaxonConfigurator config) {
831
        UUID configSecUuid = config.getSecUuid();
832
        if (configSecUuid == null){
833
            return false;
834
        }
835
        UUID taxonSecUuid = (taxon.getSec() == null)? null : taxon.getSec().getUuid();
836
        return configSecUuid.equals(taxonSecUuid);
837
    }
838

    
839
    /* (non-Javadoc)
840
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
841
     */
842
    @Override
843
    public Synonym findBestMatchingSynonym(String taxonName) {
844
        List<TaxonBase> synonymList = dao.findByNameTitleCache(Synonym.class, taxonName, null, MatchMode.EXACT, null, 0, null, null);
845
        if(! synonymList.isEmpty()){
846
            Synonym result = CdmBase.deproxy(synonymList.iterator().next(), Synonym.class);
847
            if(synonymList.size() == 1){
848
                logger.info(synonymList.size() + " Synonym found " + result.getTitleCache() );
849
                return result;
850
            } else {
851
                logger.info("Several matching synonyms found. Using first: " +  result.getTitleCache());
852
                return result;
853
            }
854
        }
855
        return null;
856
    }
857

    
858
    /* (non-Javadoc)
859
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#moveSynonymToAnotherTaxon(eu.etaxonomy.cdm.model.taxon.SynonymRelationship, eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.reference.Reference, java.lang.String)
860
     */
861
    @Override
862
    public Taxon moveSynonymToAnotherTaxon(SynonymRelationship synonymRelation,
863
            Taxon toTaxon, SynonymRelationshipType synonymRelationshipType, Reference reference, String referenceDetail) {
864
        Taxon fromTaxon = synonymRelation.getAcceptedTaxon();
865

    
866
        toTaxon.addSynonym(synonymRelation.getSynonym(), synonymRelationshipType, reference, referenceDetail);
867

    
868
        fromTaxon.removeSynonymRelation(synonymRelation);
869

    
870
        return toTaxon;
871
    }
872

    
873
    /* (non-Javadoc)
874
     * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
875
     */
876
    @Override
877
    public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheTaxon() {
878
        return dao.getUuidAndTitleCacheTaxon();
879
    }
880

    
881
	/* (non-Javadoc)
882
	 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
883
	 */
884
	@Override
885
	public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheSynonym() {
886
		return dao.getUuidAndTitleCacheSynonym();
887
	}
888

    
889
}
(71-71/76)