3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
11 package eu
.etaxonomy
.cdm
.api
.service
;
13 import java
.util
.ArrayList
;
14 import java
.util
.HashSet
;
15 import java
.util
.List
;
17 import java
.util
.UUID
;
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
;
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
.config
.NameDeletionConfigurator
;
29 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
30 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
31 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
32 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
33 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
34 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
35 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
36 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
37 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
38 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
39 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
40 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
41 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
42 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
43 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
44 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
45 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
46 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
47 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
48 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
49 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
50 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
51 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
52 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
53 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
54 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
55 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
56 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
57 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
58 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
59 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
60 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
61 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
62 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
63 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
64 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
68 * @author a.kohlbecker
73 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
74 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
75 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
78 private ITaxonNameDao nameDao
;
81 private IOrderedTermVocabularyDao orderedVocabularyDao
;
84 private INameService nameService
;
89 public TaxonServiceImpl(){
90 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
94 * FIXME Candidate for harmonization
95 * rename searchByName ?
97 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
98 return dao
.getTaxaByName(name
, sec
);
102 * FIXME Candidate for harmonization
103 * list(Synonym.class, ...)
105 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
107 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
108 return dao
.getAllSynonyms(limit
, start
);
112 * FIXME Candidate for harmonization
113 * list(Taxon.class, ...)
115 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
117 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
118 return dao
.getAllTaxa(limit
, start
);
122 * FIXME Candidate for harmonization
123 * merge with getRootTaxa(Reference sec, ..., ...)
125 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
127 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
128 if (cdmFetch
== null){
129 cdmFetch
= CdmFetch
.NO_FETCH();
131 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
136 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
138 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
139 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
143 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
145 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
146 return dao
.getAllRelationships(limit
, start
);
150 * FIXME Candidate for harmonization
151 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
154 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
156 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
157 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
158 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
159 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
160 return taxonRelTypeVocabulary
;
167 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
169 @Transactional(readOnly
= false)
170 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
172 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
173 synonymName
.removeTaxonBase(synonym
);
174 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
175 taxonName
.removeTaxonBase(acceptedTaxon
);
177 synonym
.setName(taxonName
);
178 acceptedTaxon
.setName(synonymName
);
180 // the accepted taxon needs a new uuid because the concept has changed
181 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
182 //acceptedTaxon.setUuid(UUID.randomUUID());
187 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
189 //TODO correct delete handling still needs to be implemented / checked
191 @Transactional(readOnly
= false)
192 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
194 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
195 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
196 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
198 //check synonym is not homotypic
199 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
200 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
201 throw new HomotypicalGroupChangeException(message
);
204 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
206 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
207 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
209 for (Synonym heteroSynonym
: heteroSynonyms
){
210 if (synonym
.equals(heteroSynonym
)){
211 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
213 //move synonyms in same homotypic group to new accepted taxon
214 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
218 //synonym.getName().removeTaxonBase(synonym);
219 //TODO correct delete handling still needs to be implemented / checked
221 // deleteSynonym(synonym, taxon, false);
224 this.delete(synonym
);
226 } catch (Exception e
) {
227 logger
.info("Can't delete old synonym from database");
231 return newAcceptedTaxon
;
235 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
237 // Get name from synonym
238 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
240 // remove synonym from taxon
241 toTaxon
.removeSynonym(synonym
);
243 // Create a taxon with synonym name
244 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
246 // Add taxon relation
247 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
249 // since we are swapping names, we have to detach the name from the synonym completely.
250 // Otherwise the synonym will still be in the list of typified names.
251 synonym
.getName().removeTaxonBase(synonym
);
258 * @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)
260 @Transactional(readOnly
= false)
262 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
263 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
265 TaxonNameBase synonymName
= synonym
.getName();
266 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
270 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
271 newHomotypicalGroup
.addTypifiedName(synonymName
);
273 //remove existing basionym relationships
274 synonymName
.removeBasionyms();
276 //add basionym relationship
277 if (setBasionymRelationIfApplicable
){
278 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
279 for (TaxonNameBase basionym
: basionyms
){
280 synonymName
.addBasionym(basionym
);
284 //set synonym relationship correctly
285 // SynonymRelationship relToTaxon = null;
286 boolean relToTargetTaxonExists
= false;
287 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
288 for (SynonymRelationship rel
: existingRelations
){
289 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
290 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
291 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
292 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
293 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
294 rel
.setType(newRelationType
);
295 //TODO handle citation and microCitation
298 relToTargetTaxonExists
= true;
300 if (removeFromOtherTaxa
){
301 acceptedTaxon
.removeSynonym(synonym
, false);
307 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
308 Taxon acceptedTaxon
= targetTaxon
;
309 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
310 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
311 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
312 //TODO handle citation and microCitation
313 Reference citation
= null;
314 String microCitation
= null;
315 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
322 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
325 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
327 clazz
= TaxonBase
.class;
329 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
333 protected void setDao(ITaxonDao dao
) {
338 * @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)
340 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
341 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
343 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
344 if(numberOfResults
> 0) { // no point checking again
345 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
348 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
352 * @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)
354 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
355 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
357 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
358 if(numberOfResults
> 0) { // no point checking again
359 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
366 * @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)
368 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
369 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
371 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
372 if(numberOfResults
> 0) { // no point checking again
373 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
379 * @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)
381 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
382 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
384 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
385 if(numberOfResults
> 0) { // no point checking again
386 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
388 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
392 * @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)
394 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
395 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
397 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
398 if(numberOfResults
> 0) { // no point checking again
399 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
405 * @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)
407 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
408 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
410 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
411 if(numberOfResults
> 0) { // no point checking again
412 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
414 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
418 * @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)
420 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
421 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
423 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
424 if(numberOfResults
> 0) { // no point checking again
425 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
428 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
432 * @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)
434 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
435 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
437 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
438 if(numberOfResults
> 0) { // no point checking again
439 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
442 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
446 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
448 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
449 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
450 return t
.getHomotypicSynonymsByHomotypicGroup();
454 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
456 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
457 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
458 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
459 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
460 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
461 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
463 return heterotypicSynonymyGroups
;
466 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator
){
468 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
469 Class
<?
extends TaxonBase
> clazz
= null;
470 if ((configurator
.isDoTaxa() && configurator
.isDoSynonyms())) {
471 clazz
= TaxonBase
.class;
472 //propertyPath.addAll(configurator.getTaxonPropertyPath());
473 //propertyPath.addAll(configurator.getSynonymPropertyPath());
474 } else if(configurator
.isDoTaxa()) {
476 //propertyPath = configurator.getTaxonPropertyPath();
477 } else if (configurator
.isDoSynonyms()) {
478 clazz
= Synonym
.class;
479 //propertyPath = configurator.getSynonymPropertyPath();
483 result
= dao
.getTaxaByNameForEditor(clazz
, configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
488 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
490 public Pager
<IdentifiableEntity
> findTaxaAndNames(ITaxonServiceConfigurator configurator
) {
492 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
493 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
494 List
<TaxonBase
> taxa
= null;
497 long numberTaxaResults
= 0L;
499 Class
<?
extends TaxonBase
> clazz
= null;
500 List
<String
> propertyPath
= new ArrayList
<String
>();
501 if(configurator
.getTaxonPropertyPath() != null){
502 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
504 if ((configurator
.isDoTaxa() && configurator
.isDoSynonyms())) {
505 clazz
= TaxonBase
.class;
506 //propertyPath.addAll(configurator.getTaxonPropertyPath());
507 //propertyPath.addAll(configurator.getSynonymPropertyPath());
508 } else if(configurator
.isDoTaxa()) {
510 //propertyPath = configurator.getTaxonPropertyPath();
511 } else if (configurator
.isDoSynonyms()) {
512 clazz
= Synonym
.class;
513 //propertyPath = configurator.getSynonymPropertyPath();
517 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
519 dao
.countTaxaByName(clazz
,
520 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
521 configurator
.getNamedAreas());
524 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
525 taxa
= dao
.getTaxaByName(clazz
,
526 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
527 configurator
.getNamedAreas(), configurator
.getPageSize(),
528 configurator
.getPageNumber(), propertyPath
);
532 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
535 results
.addAll(taxa
);
538 numberOfResults
+= numberTaxaResults
;
540 // Names without taxa
541 if (configurator
.isDoNamesWithoutTaxa()) {
542 int numberNameResults
= 0;
544 List
<?
extends TaxonNameBase
<?
,?
>> names
=
545 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
546 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
547 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
548 if (names
.size() > 0) {
549 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
550 if (taxonName
.getTaxonBases().size() == 0) {
551 results
.add(taxonName
);
555 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
556 numberOfResults
+= numberNameResults
;
560 // Taxa from common names
562 if (configurator
.isDoTaxaByCommonNames()) {
564 numberTaxaResults
= 0;
565 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
566 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
568 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
569 taxa
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
572 results
.addAll(taxa
);
574 numberOfResults
+= numberTaxaResults
;
578 return new DefaultPagerImpl
<IdentifiableEntity
>
579 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
582 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
583 return dao
.getUuidAndTitleCache();
587 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
589 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
590 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
591 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
592 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
593 for (TaxonDescription taxDesc
: descriptions
){
594 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
595 for (DescriptionElementBase descElem
: elements
){
596 for(Media media
: descElem
.getMedia()){
598 //find the best matching representation
599 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
608 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
610 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
611 return this.dao
.findById(listOfIDs
);
615 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
617 public int countAllRelationships() {
618 return this.dao
.countAllRelationships();
622 * @see eu.etaxonomy.cdm.api.service.ITaxonService#createAllInferredSynonyms(eu.etaxonomy.cdm.model.taxon.Classification, eu.etaxonomy.cdm.model.taxon.Taxon)
624 public List
<Synonym
> createAllInferredSynonyms(Classification tree
,
627 return this.dao
.createAllInferredSynonyms(taxon
, tree
);
631 * @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)
633 public List
<Synonym
> createInferredSynonyms(Classification tree
, Taxon taxon
, SynonymRelationshipType type
) {
634 return this.dao
.createInferredSynonyms(taxon
, tree
, type
);
638 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
640 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
641 return this.dao
.findIdenticalTaxonNames(propertyPath
);
646 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
648 @Transactional(readOnly
= false)
650 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
651 if (synonym
== null){
654 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
656 //remove synonymRelationship
657 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
661 taxonSet
.addAll(synonym
.getAcceptedTaxa());
663 for (Taxon relatedTaxon
: taxonSet
){
664 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
665 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
667 this.saveOrUpdate(synonym
);
669 //TODO remove name from homotypical group?
671 //remove synonym (if necessary)
672 if (synonym
.getSynonymRelations().isEmpty()){
673 TaxonNameBase
<?
,?
> name
= synonym
.getName();
674 synonym
.setName(null);
677 //remove name if possible (and required)
678 if (name
!= null && removeNameIfPossible
){
680 nameService
.delete(name
, new NameDeletionConfigurator());
681 }catch (DataChangeNoRollbackException ex
){
682 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
690 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
692 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
694 return this.dao
.findIdenticalNamesNew(propertyPath
);
698 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
700 public String
getPhylumName(TaxonNameBase name
){
701 return this.dao
.getPhylumName(name
);
705 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
707 public long deleteSynonymRelationships(Synonym syn
) {
708 return dao
.deleteSynonymRelationships(syn
, null);
713 * @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)
715 public List
<SynonymRelationship
> listSynonymRelationships(
716 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
717 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
718 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
720 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
721 if(numberOfResults
> 0) { // no point checking again
722 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
728 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
731 public Taxon
findBestMatchingTaxon(String taxonName
) {
732 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
733 config
.setTaxonNameTitle(taxonName
);
734 return findBestMatchingTaxon(config
);
740 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
742 Taxon bestCandidate
= null;
744 // 1. search for acceptet taxa
745 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(Taxon
.class, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
746 boolean bestCandidateMatchesSecUuid
= false;
747 boolean bestCandidateIsInClassification
= false;
748 int countEqualCandidates
= 0;
749 for(TaxonBase taxonBaseCandidate
: taxonList
){
750 if(taxonBaseCandidate
instanceof Taxon
){
751 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
752 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
753 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
755 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
756 bestCandidate
= newCanditate
;
757 countEqualCandidates
= 1;
758 bestCandidateMatchesSecUuid
= true;
762 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
763 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
765 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
766 bestCandidate
= newCanditate
;
767 countEqualCandidates
= 1;
768 bestCandidateIsInClassification
= true;
771 if (bestCandidate
== null){
772 bestCandidate
= newCanditate
;
773 countEqualCandidates
= 1;
777 }else{ //not Taxon.class
780 countEqualCandidates
++;
783 if (bestCandidate
!= null){
784 if(countEqualCandidates
> 1){
785 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
786 return bestCandidate
;
788 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
789 return bestCandidate
;
794 // 2. search for synonyms
795 if (config
.isIncludeSynonyms()){
796 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(Synonym
.class, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
797 for(TaxonBase taxonBase
: synonymList
){
798 if(taxonBase
instanceof Synonym
){
799 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
800 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
801 if(!acceptetdCandidates
.isEmpty()){
802 bestCandidate
= acceptetdCandidates
.iterator().next();
803 if(acceptetdCandidates
.size() == 1){
804 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
805 return bestCandidate
;
807 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
808 return bestCandidate
;
810 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
816 } catch (Exception e
){
820 return bestCandidate
;
823 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
824 UUID configClassificationUuid
= config
.getClassificationUuid();
825 if (configClassificationUuid
== null){
828 for (TaxonNode node
: taxon
.getTaxonNodes()){
829 UUID classUuid
= node
.getClassification().getUuid();
830 if (configClassificationUuid
.equals(classUuid
)){
837 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
838 UUID configSecUuid
= config
.getSecUuid();
839 if (configSecUuid
== null){
842 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
843 return configSecUuid
.equals(taxonSecUuid
);
847 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
850 public Synonym
findBestMatchingSynonym(String taxonName
) {
851 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(Synonym
.class, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
852 if(! synonymList
.isEmpty()){
853 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
854 if(synonymList
.size() == 1){
855 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
858 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
867 * @see eu.etaxonomy.cdm.api.service.ITaxonService#moveSynonymToAnotherTaxon(eu.etaxonomy.cdm.model.taxon.SynonymRelationship, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, eu.etaxonomy.cdm.model.reference.Reference, java.lang.String, boolean)
870 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
871 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
873 Synonym synonym
= oldSynonymRelation
.getSynonym();
874 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
875 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
876 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
877 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
878 //set default relationship type
879 if (newSynonymRelationshipType
== null){
880 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
882 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
884 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
885 int hgSize
= homotypicGroup
.getTypifiedNames().size();
886 boolean isSingleInGroup
= !(hgSize
> 1);
888 if (! isSingleInGroup
){
889 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
890 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
891 if (isHomotypicToAccepted
){
892 String message
= "Synonym is in homotypic group with accepted taxon%s. First remove synonym from homotypic group of accepted taxon before moving to other taxon.";
893 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
894 message
= String
.format(message
, homotypicRelatives
);
895 throw new HomotypicalGroupChangeException(message
);
897 if (! moveHomotypicGroup
){
898 String message
= "Synonym is in homotypic group with other synonym(s). Either move complete homotypic group or remove synonym from homotypic group prior to moving to other taxon.";
899 throw new HomotypicalGroupChangeException(message
);
902 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
904 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
906 SynonymRelationship result
= null;
907 //move all synonyms to new taxon
908 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
909 for (Synonym syn
: homotypicSynonyms
){
910 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
911 for (SynonymRelationship synRelation
: synRelations
){
912 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
913 Reference
<?
> newReference
= reference
;
914 if (newReference
== null && keepReference
){
915 newReference
= synRelation
.getCitation();
917 String newRefDetail
= referenceDetail
;
918 if (newRefDetail
== null && keepReference
){
919 newRefDetail
= synRelation
.getCitationMicroReference();
921 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
922 fromTaxon
.removeSynonymRelation(synRelation
, false);
924 //change homotypic group of synonym if relType is 'homotypic'
925 // if (newRelTypeIsHomotypic){
926 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
929 if (synRelation
.equals(oldSynonymRelation
)){
930 result
= newSynRelation
;
936 saveOrUpdate(newTaxon
);
937 //Assert that there is a result
939 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
940 throw new IllegalStateException(message
);
946 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
949 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
950 return dao
.getUuidAndTitleCacheTaxon();
954 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
957 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
958 return dao
.getUuidAndTitleCacheSynonym();