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
.io
.IOException
;
14 import java
.util
.ArrayList
;
15 import java
.util
.HashMap
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
19 import java
.util
.UUID
;
21 import org
.apache
.log4j
.Logger
;
22 import org
.apache
.lucene
.index
.CorruptIndexException
;
23 import org
.apache
.lucene
.queryParser
.ParseException
;
24 import org
.apache
.lucene
.search
.TopDocs
;
25 import org
.hibernate
.criterion
.Criterion
;
26 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
27 import org
.springframework
.stereotype
.Service
;
28 import org
.springframework
.transaction
.annotation
.Propagation
;
29 import org
.springframework
.transaction
.annotation
.Transactional
;
31 import eu
.etaxonomy
.cdm
.api
.service
.config
.ITaxonServiceConfigurator
;
32 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
33 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
34 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
35 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
36 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
37 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
38 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
39 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
40 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
41 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
42 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
43 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
44 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
45 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
46 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
47 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
48 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
49 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
50 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
51 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
52 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
53 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
54 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
55 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
56 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
57 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
58 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
59 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
60 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
61 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
62 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
63 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
64 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
65 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
66 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
67 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
68 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
69 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
70 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
71 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
72 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
73 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
74 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
75 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
76 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
77 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
78 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
79 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
80 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
81 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
82 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
83 import eu
.etaxonomy
.cdm
.search
.LuceneSearch
;
84 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
88 * @author a.kohlbecker
93 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
94 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
95 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
97 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
99 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
101 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
105 private ITaxonNameDao nameDao
;
108 private ISearchResultBuilder searchResultBuilder
;
111 private INameService nameService
;
114 private ICdmGenericDao genericDao
;
117 private IDescriptionService descriptionService
;
120 private IOrderedTermVocabularyDao orderedVocabularyDao
;
125 public TaxonServiceImpl(){
126 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
130 * FIXME Candidate for harmonization
131 * rename searchByName ?
133 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
134 return dao
.getTaxaByName(name
, sec
);
138 * FIXME Candidate for harmonization
139 * list(Synonym.class, ...)
141 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
143 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
144 return dao
.getAllSynonyms(limit
, start
);
148 * FIXME Candidate for harmonization
149 * list(Taxon.class, ...)
151 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
153 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
154 return dao
.getAllTaxa(limit
, start
);
158 * FIXME Candidate for harmonization
159 * merge with getRootTaxa(Reference sec, ..., ...)
161 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
163 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
164 if (cdmFetch
== null){
165 cdmFetch
= CdmFetch
.NO_FETCH();
167 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
172 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
174 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
175 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
179 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
181 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
182 return dao
.getAllRelationships(limit
, start
);
186 * FIXME Candidate for harmonization
187 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
190 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
192 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
193 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
194 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
195 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
196 return taxonRelTypeVocabulary
;
203 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
205 @Transactional(readOnly
= false)
206 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
208 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
209 synonymName
.removeTaxonBase(synonym
);
210 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
211 taxonName
.removeTaxonBase(acceptedTaxon
);
213 synonym
.setName(taxonName
);
214 acceptedTaxon
.setName(synonymName
);
216 // the accepted taxon needs a new uuid because the concept has changed
217 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
218 //acceptedTaxon.setUuid(UUID.randomUUID());
223 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
225 //TODO correct delete handling still needs to be implemented / checked
227 @Transactional(readOnly
= false)
228 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
230 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
231 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
232 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
234 //check synonym is not homotypic
235 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
236 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
237 throw new HomotypicalGroupChangeException(message
);
240 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
242 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
243 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
245 for (Synonym heteroSynonym
: heteroSynonyms
){
246 if (synonym
.equals(heteroSynonym
)){
247 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
249 //move synonyms in same homotypic group to new accepted taxon
250 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
254 //synonym.getName().removeTaxonBase(synonym);
255 //TODO correct delete handling still needs to be implemented / checked
257 // deleteSynonym(synonym, taxon, false);
260 this.delete(synonym
);
262 } catch (Exception e
) {
263 logger
.info("Can't delete old synonym from database");
267 return newAcceptedTaxon
;
271 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
273 // Get name from synonym
274 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
276 // remove synonym from taxon
277 toTaxon
.removeSynonym(synonym
);
279 // Create a taxon with synonym name
280 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
282 // Add taxon relation
283 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
285 // since we are swapping names, we have to detach the name from the synonym completely.
286 // Otherwise the synonym will still be in the list of typified names.
287 synonym
.getName().removeTaxonBase(synonym
);
294 * @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)
296 @Transactional(readOnly
= false)
298 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
299 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
301 TaxonNameBase synonymName
= synonym
.getName();
302 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
306 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
307 newHomotypicalGroup
.addTypifiedName(synonymName
);
309 //remove existing basionym relationships
310 synonymName
.removeBasionyms();
312 //add basionym relationship
313 if (setBasionymRelationIfApplicable
){
314 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
315 for (TaxonNameBase basionym
: basionyms
){
316 synonymName
.addBasionym(basionym
);
320 //set synonym relationship correctly
321 // SynonymRelationship relToTaxon = null;
322 boolean relToTargetTaxonExists
= false;
323 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
324 for (SynonymRelationship rel
: existingRelations
){
325 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
326 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
327 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
328 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
329 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
330 rel
.setType(newRelationType
);
331 //TODO handle citation and microCitation
334 relToTargetTaxonExists
= true;
336 if (removeFromOtherTaxa
){
337 acceptedTaxon
.removeSynonym(synonym
, false);
343 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
344 Taxon acceptedTaxon
= targetTaxon
;
345 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
346 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
347 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
348 //TODO handle citation and microCitation
349 Reference citation
= null;
350 String microCitation
= null;
351 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
358 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
361 @Transactional(readOnly
= false)
362 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
364 clazz
= TaxonBase
.class;
366 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
370 protected void setDao(ITaxonDao dao
) {
375 * @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)
377 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
378 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
380 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
381 if(numberOfResults
> 0) { // no point checking again
382 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
385 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
389 * @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)
391 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
392 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
394 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
395 if(numberOfResults
> 0) { // no point checking again
396 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
403 * @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)
405 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
406 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
408 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
409 if(numberOfResults
> 0) { // no point checking again
410 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
416 * @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)
418 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
419 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
421 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
422 if(numberOfResults
> 0) { // no point checking again
423 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
425 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
429 * @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)
431 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
432 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
434 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
435 if(numberOfResults
> 0) { // no point checking again
436 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
442 * @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)
444 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
445 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
447 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
448 if(numberOfResults
> 0) { // no point checking again
449 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
451 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
455 * @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)
457 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
458 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
460 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
461 if(numberOfResults
> 0) { // no point checking again
462 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
465 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
469 * @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)
471 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
472 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
474 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
475 if(numberOfResults
> 0) { // no point checking again
476 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
479 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
483 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
485 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
486 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
487 return t
.getHomotypicSynonymsByHomotypicGroup();
491 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
493 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
494 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
495 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
496 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
497 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
498 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
500 return heterotypicSynonymyGroups
;
503 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator
){
505 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
506 // Class<? extends TaxonBase> clazz = null;
507 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
508 // clazz = TaxonBase.class;
509 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
510 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
511 // } else if(configurator.isDoTaxa()) {
512 // clazz = Taxon.class;
513 // //propertyPath = configurator.getTaxonPropertyPath();
514 // } else if (configurator.isDoSynonyms()) {
515 // clazz = Synonym.class;
516 // //propertyPath = configurator.getSynonymPropertyPath();
520 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
525 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
527 public Pager
<IdentifiableEntity
> findTaxaAndNames(ITaxonServiceConfigurator configurator
) {
529 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
530 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
531 List
<TaxonBase
> taxa
= null;
534 long numberTaxaResults
= 0L;
537 List
<String
> propertyPath
= new ArrayList
<String
>();
538 if(configurator
.getTaxonPropertyPath() != null){
539 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
543 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
544 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
546 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
547 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
548 configurator
.getNamedAreas());
551 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
552 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
553 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
554 configurator
.getMatchMode(), configurator
.getNamedAreas(),
555 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
559 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
562 results
.addAll(taxa
);
565 numberOfResults
+= numberTaxaResults
;
567 // Names without taxa
568 if (configurator
.isDoNamesWithoutTaxa()) {
569 int numberNameResults
= 0;
571 List
<?
extends TaxonNameBase
<?
,?
>> names
=
572 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
573 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
574 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
575 if (names
.size() > 0) {
576 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
577 if (taxonName
.getTaxonBases().size() == 0) {
578 results
.add(taxonName
);
582 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
583 numberOfResults
+= numberNameResults
;
587 // Taxa from common names
589 if (configurator
.isDoTaxaByCommonNames()) {
590 taxa
= new ArrayList
<TaxonBase
>();
591 numberTaxaResults
= 0;
592 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
593 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
595 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
596 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
597 for( Object
[] entry
: commonNameResults
) {
598 taxa
.add((TaxonBase
) entry
[0]);
602 results
.addAll(taxa
);
604 numberOfResults
+= numberTaxaResults
;
608 return new DefaultPagerImpl
<IdentifiableEntity
>
609 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
612 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
613 return dao
.getUuidAndTitleCache();
617 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
619 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
620 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
621 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
622 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
623 for (TaxonDescription taxDesc
: descriptions
){
624 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
625 for (DescriptionElementBase descElem
: elements
){
626 for(Media media
: descElem
.getMedia()){
628 //find the best matching representation
629 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
638 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
640 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
641 return this.dao
.findById(listOfIDs
);
645 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
647 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
648 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
652 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
654 public int countAllRelationships() {
655 return this.dao
.countAllRelationships();
662 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
664 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
665 return this.dao
.findIdenticalTaxonNames(propertyPath
);
670 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
673 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
675 config
= new TaxonDeletionConfigurator();
679 if (! config
.isDeleteTaxonNodes()){
680 if (taxon
.getTaxonNodes().size() > 0){
681 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
682 throw new ReferencedObjectUndeletableException(message
);
687 // SynonymRelationShip
688 if (config
.isDeleteSynonymRelations()){
689 boolean removeSynonymNameFromHomotypicalGroup
= false;
690 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
691 Synonym synonym
= synRel
.getSynonym();
692 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
693 if (config
.isDeleteSynonymsIfPossible()){
695 boolean newHomotypicGroupIfNeeded
= true;
696 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
698 deleteSynonymRelationships(synonym
, taxon
);
704 if (! config
.isDeleteTaxonRelationships()){
705 if (taxon
.getTaxonRelations().size() > 0){
706 String message
= "Taxon can't be deleted as it is related to another taxon. Remove taxon from all relations to other taxa prior to deletion.";
707 throw new ReferencedObjectUndeletableException(message
);
713 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
715 for (TaxonDescription desc
: descriptions
){
716 if (config
.isDeleteDescriptions()){
717 //TODO use description delete configurator ?
718 //FIXME check if description is ALWAYS deletable
719 descriptionService
.delete(desc
);
721 if (desc
.getDescribedSpecimenOrObservations().size()>0){
722 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
723 " which also describes specimens or abservations";
724 throw new ReferencedObjectUndeletableException(message
);
730 //check references with only reverse mapping
731 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
732 for (CdmBase referencingObject
: referencingObjects
){
733 //IIdentificationKeys (Media, Polytomous, MultiAccess)
734 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
735 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
736 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
737 throw new ReferencedObjectUndeletableException(message
);
742 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
743 String message
= "Taxon can't be deleted as it is used in polytomous key node";
744 throw new ReferencedObjectUndeletableException(message
);
748 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
749 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
750 throw new ReferencedObjectUndeletableException(message
);
756 if (config
.isDeleteNameIfPossible()){
758 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
759 } catch (ReferencedObjectUndeletableException e
) {
761 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
768 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
770 @Transactional(readOnly
= false)
772 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
773 if (synonym
== null){
776 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
778 //remove synonymRelationship
779 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
783 taxonSet
.addAll(synonym
.getAcceptedTaxa());
785 for (Taxon relatedTaxon
: taxonSet
){
786 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
787 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
789 this.saveOrUpdate(synonym
);
791 //TODO remove name from homotypical group?
793 //remove synonym (if necessary)
794 if (synonym
.getSynonymRelations().isEmpty()){
795 TaxonNameBase
<?
,?
> name
= synonym
.getName();
796 synonym
.setName(null);
799 //remove name if possible (and required)
800 if (name
!= null && removeNameIfPossible
){
802 nameService
.delete(name
, new NameDeletionConfigurator());
803 }catch (DataChangeNoRollbackException ex
){
804 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
812 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
814 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
816 return this.dao
.findIdenticalNamesNew(propertyPath
);
820 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
822 public String
getPhylumName(TaxonNameBase name
){
823 return this.dao
.getPhylumName(name
);
827 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
829 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
830 return dao
.deleteSynonymRelationships(syn
, taxon
);
834 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
836 public long deleteSynonymRelationships(Synonym syn
) {
837 return dao
.deleteSynonymRelationships(syn
, null);
842 * @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)
844 public List
<SynonymRelationship
> listSynonymRelationships(
845 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
846 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
847 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
849 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
850 if(numberOfResults
> 0) { // no point checking again
851 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
857 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
860 public Taxon
findBestMatchingTaxon(String taxonName
) {
861 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
862 config
.setTaxonNameTitle(taxonName
);
863 return findBestMatchingTaxon(config
);
869 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
871 Taxon bestCandidate
= null;
873 // 1. search for acceptet taxa
874 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
875 boolean bestCandidateMatchesSecUuid
= false;
876 boolean bestCandidateIsInClassification
= false;
877 int countEqualCandidates
= 0;
878 for(TaxonBase taxonBaseCandidate
: taxonList
){
879 if(taxonBaseCandidate
instanceof Taxon
){
880 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
881 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
882 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
884 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
885 bestCandidate
= newCanditate
;
886 countEqualCandidates
= 1;
887 bestCandidateMatchesSecUuid
= true;
891 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
892 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
894 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
895 bestCandidate
= newCanditate
;
896 countEqualCandidates
= 1;
897 bestCandidateIsInClassification
= true;
900 if (bestCandidate
== null){
901 bestCandidate
= newCanditate
;
902 countEqualCandidates
= 1;
906 }else{ //not Taxon.class
909 countEqualCandidates
++;
912 if (bestCandidate
!= null){
913 if(countEqualCandidates
> 1){
914 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
915 return bestCandidate
;
917 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
918 return bestCandidate
;
923 // 2. search for synonyms
924 if (config
.isIncludeSynonyms()){
925 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
926 for(TaxonBase taxonBase
: synonymList
){
927 if(taxonBase
instanceof Synonym
){
928 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
929 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
930 if(!acceptetdCandidates
.isEmpty()){
931 bestCandidate
= acceptetdCandidates
.iterator().next();
932 if(acceptetdCandidates
.size() == 1){
933 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
934 return bestCandidate
;
936 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
937 return bestCandidate
;
939 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
945 } catch (Exception e
){
949 return bestCandidate
;
952 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
953 UUID configClassificationUuid
= config
.getClassificationUuid();
954 if (configClassificationUuid
== null){
957 for (TaxonNode node
: taxon
.getTaxonNodes()){
958 UUID classUuid
= node
.getClassification().getUuid();
959 if (configClassificationUuid
.equals(classUuid
)){
966 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
967 UUID configSecUuid
= config
.getSecUuid();
968 if (configSecUuid
== null){
971 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
972 return configSecUuid
.equals(taxonSecUuid
);
976 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
979 public Synonym
findBestMatchingSynonym(String taxonName
) {
980 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
981 if(! synonymList
.isEmpty()){
982 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
983 if(synonymList
.size() == 1){
984 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
987 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
996 * @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)
999 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1000 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1002 Synonym synonym
= oldSynonymRelation
.getSynonym();
1003 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1004 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1005 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1006 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1007 //set default relationship type
1008 if (newSynonymRelationshipType
== null){
1009 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1011 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1013 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1014 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1015 boolean isSingleInGroup
= !(hgSize
> 1);
1017 if (! isSingleInGroup
){
1018 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1019 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1020 if (isHomotypicToAccepted
){
1021 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.";
1022 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1023 message
= String
.format(message
, homotypicRelatives
);
1024 throw new HomotypicalGroupChangeException(message
);
1026 if (! moveHomotypicGroup
){
1027 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.";
1028 throw new HomotypicalGroupChangeException(message
);
1031 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1033 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1035 SynonymRelationship result
= null;
1036 //move all synonyms to new taxon
1037 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1038 for (Synonym syn
: homotypicSynonyms
){
1039 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1040 for (SynonymRelationship synRelation
: synRelations
){
1041 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1042 Reference
<?
> newReference
= reference
;
1043 if (newReference
== null && keepReference
){
1044 newReference
= synRelation
.getCitation();
1046 String newRefDetail
= referenceDetail
;
1047 if (newRefDetail
== null && keepReference
){
1048 newRefDetail
= synRelation
.getCitationMicroReference();
1050 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1051 fromTaxon
.removeSynonymRelation(synRelation
, false);
1053 //change homotypic group of synonym if relType is 'homotypic'
1054 // if (newRelTypeIsHomotypic){
1055 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1058 if (synRelation
.equals(oldSynonymRelation
)){
1059 result
= newSynRelation
;
1065 saveOrUpdate(newTaxon
);
1066 //Assert that there is a result
1067 if (result
== null){
1068 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1069 throw new IllegalStateException(message
);
1075 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1078 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1079 return dao
.getUuidAndTitleCacheTaxon();
1083 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1086 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1087 return dao
.getUuidAndTitleCacheSynonym();
1091 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(Class
<?
extends DescriptionElementBase
> clazz
, String queryString
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
1092 List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1094 String luceneQueryTemplate
= "titleCache:%1$s OR text.ALL:%1$s OR name:%1$s";
1095 String luceneQuery
= String
.format(luceneQueryTemplate
, queryString
);
1097 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), clazz
);
1098 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(luceneQuery
);
1099 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSetFromIds(luceneSearch
, topDocsResultSet
, dao
, "inDescription.taxon.id");
1101 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
1105 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1106 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1107 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1109 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1112 UUID uuid
= taxon
.getName().getUuid();
1113 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1114 String epithetOfTaxon
= null;
1115 String infragenericEpithetOfTaxon
= null;
1116 String infraspecificEpithetOfTaxon
= null;
1117 if (taxonName
.isSpecies()){
1118 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1119 } else if (taxonName
.isInfraGeneric()){
1120 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1121 } else if (taxonName
.isInfraSpecific()){
1122 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1124 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1125 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1126 List
<String
> taxonNames
= new ArrayList
<String
>();
1128 for (TaxonNode node
: nodes
){
1129 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1130 // List<String> synonymsEpithet = new ArrayList<String>();
1132 if (node
.getClassification().equals(classification
)){
1133 if (!node
.isTopmostNode()){
1134 TaxonNode parent
= (TaxonNode
)node
.getParent();
1135 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1136 TaxonNameBase parentName
= parent
.getTaxon().getName();
1137 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1138 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1139 Rank rankOfTaxon
= taxonName
.getRank();
1142 //create inferred synonyms for species, subspecies
1143 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1145 Synonym inferredEpithet
= null;
1146 Synonym inferredGenus
= null;
1147 Synonym potentialCombination
= null;
1149 List
<String
> propertyPaths
= new ArrayList
<String
>();
1150 propertyPaths
.add("synonym");
1151 propertyPaths
.add("synonym.name");
1152 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1153 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1155 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1156 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1158 List
<TaxonRelationship
> taxonRelListParent
= null;
1159 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1160 if (doWithMisappliedNames
){
1161 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1162 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1166 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1167 Set
<String
> genusNames
= new HashSet
<String
>();
1169 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1170 Synonym syn
= synonymRelationOfParent
.getSynonym();
1172 inferredEpithet
= createInferredEpithets(taxon
,
1173 zooHashMap
, taxonName
, epithetOfTaxon
,
1174 infragenericEpithetOfTaxon
,
1175 infraspecificEpithetOfTaxon
,
1176 taxonNames
, parentName
,
1180 inferredSynonyms
.add(inferredEpithet
);
1181 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1182 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1185 if (doWithMisappliedNames
){
1187 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1188 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1190 inferredEpithet
= createInferredEpithets(taxon
,
1191 zooHashMap
, taxonName
, epithetOfTaxon
,
1192 infragenericEpithetOfTaxon
,
1193 infraspecificEpithetOfTaxon
,
1194 taxonNames
, parentName
,
1197 inferredSynonyms
.add(inferredEpithet
);
1198 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1199 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1203 if (!taxonNames
.isEmpty()){
1204 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1205 ZoologicalName name
;
1206 if (!synNotInCDM
.isEmpty()){
1207 inferredSynonymsToBeRemoved
.clear();
1209 for (Synonym syn
:inferredSynonyms
){
1210 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1211 if (!synNotInCDM
.contains(name
.getNameCache())){
1212 inferredSynonymsToBeRemoved
.add(syn
);
1216 // Remove identified Synonyms from inferredSynonyms
1217 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1218 inferredSynonyms
.remove(synonym
);
1223 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1226 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1227 TaxonNameBase synName
;
1228 ZoologicalName inferredSynName
;
1230 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1231 inferredGenus
= createInferredGenus(taxon
,
1232 zooHashMap
, taxonName
, epithetOfTaxon
,
1233 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1235 inferredSynonyms
.add(inferredGenus
);
1236 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1237 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1242 if (doWithMisappliedNames
){
1244 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1245 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1246 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1248 inferredSynonyms
.add(inferredGenus
);
1249 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1250 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1255 if (!taxonNames
.isEmpty()){
1256 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1257 ZoologicalName name
;
1258 if (!synNotInCDM
.isEmpty()){
1259 inferredSynonymsToBeRemoved
.clear();
1261 for (Synonym syn
:inferredSynonyms
){
1262 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1263 if (!synNotInCDM
.contains(name
.getNameCache())){
1264 inferredSynonymsToBeRemoved
.add(syn
);
1268 // Remove identified Synonyms from inferredSynonyms
1269 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1270 inferredSynonyms
.remove(synonym
);
1275 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1277 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1278 ZoologicalName inferredSynName
;
1279 //for all synonyms of the parent...
1280 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1281 TaxonNameBase synName
;
1282 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1283 synName
= synParent
.getName();
1285 HibernateProxyHelper
.deproxy(synParent
);
1287 // Set the sourceReference
1288 sourceReference
= synParent
.getSec();
1290 // Determine the idInSource
1291 String idInSourceParent
= getIdInSource(synParent
);
1293 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1294 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1295 String synParentInfragenericName
= null;
1296 String synParentSpecificEpithet
= null;
1298 if (parentSynZooName
.isInfraGeneric()){
1299 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1301 if (parentSynZooName
.isSpecies()){
1302 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1305 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1306 synonymsGenus.put(synGenusName, idInSource);
1309 //for all synonyms of the taxon
1311 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1313 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1314 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1315 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1317 synParentInfragenericName
,
1318 synParentSpecificEpithet
, syn
, zooHashMap
);
1320 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1321 inferredSynonyms
.add(potentialCombination
);
1322 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1323 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1330 if (doWithMisappliedNames
){
1332 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1334 TaxonNameBase misappliedParentName
;
1336 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1337 misappliedParentName
= misappliedParent
.getName();
1339 HibernateProxyHelper
.deproxy(misappliedParent
);
1341 // Set the sourceReference
1342 sourceReference
= misappliedParent
.getSec();
1344 // Determine the idInSource
1345 String idInSourceParent
= getIdInSource(misappliedParent
);
1347 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1348 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1349 String synParentInfragenericName
= null;
1350 String synParentSpecificEpithet
= null;
1352 if (parentSynZooName
.isInfraGeneric()){
1353 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1355 if (parentSynZooName
.isSpecies()){
1356 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1360 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1361 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1362 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1363 potentialCombination
= createPotentialCombination(
1364 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1366 synParentInfragenericName
,
1367 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1370 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1371 inferredSynonyms
.add(potentialCombination
);
1372 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1373 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1378 if (!taxonNames
.isEmpty()){
1379 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1380 ZoologicalName name
;
1381 if (!synNotInCDM
.isEmpty()){
1382 inferredSynonymsToBeRemoved
.clear();
1383 for (Synonym syn
:inferredSynonyms
){
1385 name
= (ZoologicalName
) syn
.getName();
1386 }catch (ClassCastException e
){
1387 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1389 if (!synNotInCDM
.contains(name
.getNameCache())){
1390 inferredSynonymsToBeRemoved
.add(syn
);
1393 // Remove identified Synonyms from inferredSynonyms
1394 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1395 inferredSynonyms
.remove(synonym
);
1401 logger
.info("The synonymrelationship type is not defined.");
1402 return inferredSynonyms
;
1409 return inferredSynonyms
;
1412 private Synonym
createPotentialCombination(String idInSourceParent
,
1413 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1414 String synParentInfragenericName
, String synParentSpecificEpithet
,
1415 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1416 Synonym potentialCombination
;
1417 Reference sourceReference
;
1418 ZoologicalName inferredSynName
;
1419 HibernateProxyHelper
.deproxy(syn
);
1421 // Set sourceReference
1422 sourceReference
= syn
.getSec();
1425 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1427 String synTaxonInfraSpecificName
= null;
1429 if (parentSynZooName
.isSpecies()){
1430 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1433 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1434 synonymsEpithet.add(epithetName);
1437 //create potential combinations...
1438 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1440 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1441 if (zooSynName
.isSpecies()){
1442 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1443 if (parentSynZooName
.isInfraGeneric()){
1444 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1447 if (zooSynName
.isInfraSpecific()){
1448 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1449 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1451 if (parentSynZooName
.isInfraGeneric()){
1452 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1456 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1458 // Set the sourceReference
1459 potentialCombination
.setSec(sourceReference
);
1462 // Determine the idInSource
1463 String idInSourceSyn
= getIdInSource(syn
);
1465 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1466 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1467 inferredSynName
.addSource(originalSource
);
1468 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1469 potentialCombination
.addSource(originalSource
);
1472 inferredSynName
.generateTitle();
1474 return potentialCombination
;
1477 private Synonym
createInferredGenus(Taxon taxon
,
1478 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1479 String epithetOfTaxon
, String genusOfTaxon
,
1480 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1483 Synonym inferredGenus
;
1484 TaxonNameBase synName
;
1485 ZoologicalName inferredSynName
;
1486 synName
=syn
.getName();
1487 HibernateProxyHelper
.deproxy(syn
);
1489 // Determine the idInSource
1490 String idInSourceSyn
= getIdInSource(syn
);
1491 String idInSourceTaxon
= getIdInSource(taxon
);
1492 // Determine the sourceReference
1493 Reference sourceReference
= syn
.getSec();
1495 synName
= syn
.getName();
1496 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1497 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1498 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1499 synonymsEpithet.add(synSpeciesEpithetName);
1502 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1503 //TODO:differ between parent is genus and taxon is species, parent is subgenus and taxon is species, parent is species and taxon is subspecies and parent is genus and taxon is subgenus...
1506 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1507 if (zooParentName
.isInfraGeneric()){
1508 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1511 if (taxonName
.isSpecies()){
1512 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1514 if (taxonName
.isInfraSpecific()){
1515 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1516 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1520 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1522 // Set the sourceReference
1523 inferredGenus
.setSec(sourceReference
);
1525 // Add the original source
1526 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1527 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1528 inferredGenus
.addSource(originalSource
);
1530 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1531 inferredSynName
.addSource(originalSource
);
1535 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1537 inferredSynName
.generateTitle();
1540 return inferredGenus
;
1543 private Synonym
createInferredEpithets(Taxon taxon
,
1544 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1545 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1546 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1547 TaxonNameBase parentName
, TaxonBase syn
) {
1549 Synonym inferredEpithet
;
1550 TaxonNameBase synName
;
1551 ZoologicalName inferredSynName
;
1552 HibernateProxyHelper
.deproxy(syn
);
1554 // Determine the idInSource
1555 String idInSourceSyn
= getIdInSource(syn
);
1556 String idInSourceTaxon
= getIdInSource(taxon
);
1557 // Determine the sourceReference
1558 Reference sourceReference
= syn
.getSec();
1560 synName
= syn
.getName();
1561 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1562 String synGenusName
= zooSynName
.getGenusOrUninomial();
1563 String synInfraGenericEpithet
= null;
1564 String synSpecificEpithet
= null;
1566 if (zooSynName
.getInfraGenericEpithet() != null){
1567 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1570 if (zooSynName
.isInfraSpecific()){
1571 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1574 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1575 synonymsGenus.put(synGenusName, idInSource);
1578 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1580 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1581 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1582 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1584 inferredSynName
.setGenusOrUninomial(synGenusName
);
1586 if (parentName
.isInfraGeneric()){
1587 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1589 if (taxonName
.isSpecies()){
1590 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1591 }else if (taxonName
.isInfraSpecific()){
1592 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1593 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1596 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1598 // Set the sourceReference
1599 inferredEpithet
.setSec(sourceReference
);
1601 /* Add the original source
1602 if (idInSource != null) {
1603 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1606 Reference citation = getCitation(syn);
1607 if (citation != null) {
1608 originalSource.setCitation(citation);
1609 inferredEpithet.addSource(originalSource);
1612 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1614 IdentifiableSource originalSource
;
1615 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1617 inferredEpithet
.addSource(originalSource
);
1619 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1621 inferredSynName
.addSource(originalSource
);
1625 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1627 inferredSynName
.generateTitle();
1628 return inferredEpithet
;
1632 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1633 * Very likely only useful for createInferredSynonyms().
1638 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1639 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1640 if (taxonName
== null) {
1641 taxonName
= zooHashMap
.get(uuid
);
1647 * Returns the idInSource for a given Synonym.
1650 private String
getIdInSource(TaxonBase taxonBase
) {
1651 String idInSource
= null;
1652 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1653 if (sources
.size() == 1) {
1654 IdentifiableSource source
= sources
.iterator().next();
1655 if (source
!= null) {
1656 idInSource
= source
.getIdInSource();
1658 } else if (sources
.size() > 1) {
1661 for (IdentifiableSource source
: sources
) {
1662 idInSource
+= source
.getIdInSource();
1663 if (count
< sources
.size()) {
1675 * Returns the citation for a given Synonym.
1678 private Reference
getCitation(Synonym syn
) {
1679 Reference citation
= null;
1680 Set
<IdentifiableSource
> sources
= syn
.getSources();
1681 if (sources
.size() == 1) {
1682 IdentifiableSource source
= sources
.iterator().next();
1683 if (source
!= null) {
1684 citation
= source
.getCitation();
1686 } else if (sources
.size() > 1) {
1687 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1693 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1694 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1696 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1697 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1698 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1700 return inferredSynonyms
;