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
.hibernate
.search
.DefinedTermBaseFieldBridge
;
45 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
46 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
47 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
48 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
49 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
50 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
51 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
52 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
53 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
54 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
55 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
56 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
57 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
58 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
59 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
60 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
61 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
62 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
63 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
64 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
65 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
66 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
67 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
68 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
69 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
70 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
71 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
72 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
73 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
74 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
75 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
76 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
77 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
78 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
79 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
80 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
81 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
82 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
83 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
84 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
85 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
86 import eu
.etaxonomy
.cdm
.search
.LuceneSearch
;
87 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
91 * @author a.kohlbecker
96 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
97 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
98 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
100 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
102 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
104 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
108 private ITaxonNameDao nameDao
;
111 private ISearchResultBuilder searchResultBuilder
;
114 private INameService nameService
;
117 private ICdmGenericDao genericDao
;
120 private IDescriptionService descriptionService
;
123 private IOrderedTermVocabularyDao orderedVocabularyDao
;
128 public TaxonServiceImpl(){
129 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
133 * FIXME Candidate for harmonization
134 * rename searchByName ?
136 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
137 return dao
.getTaxaByName(name
, sec
);
141 * FIXME Candidate for harmonization
142 * list(Synonym.class, ...)
144 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
146 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
147 return dao
.getAllSynonyms(limit
, start
);
151 * FIXME Candidate for harmonization
152 * list(Taxon.class, ...)
154 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
156 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
157 return dao
.getAllTaxa(limit
, start
);
161 * FIXME Candidate for harmonization
162 * merge with getRootTaxa(Reference sec, ..., ...)
164 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
166 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
167 if (cdmFetch
== null){
168 cdmFetch
= CdmFetch
.NO_FETCH();
170 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
175 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
177 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
178 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
182 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
184 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
185 return dao
.getAllRelationships(limit
, start
);
189 * FIXME Candidate for harmonization
190 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
193 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
195 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
196 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
197 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
198 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
199 return taxonRelTypeVocabulary
;
206 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
208 @Transactional(readOnly
= false)
209 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
211 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
212 synonymName
.removeTaxonBase(synonym
);
213 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
214 taxonName
.removeTaxonBase(acceptedTaxon
);
216 synonym
.setName(taxonName
);
217 acceptedTaxon
.setName(synonymName
);
219 // the accepted taxon needs a new uuid because the concept has changed
220 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
221 //acceptedTaxon.setUuid(UUID.randomUUID());
226 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
228 //TODO correct delete handling still needs to be implemented / checked
230 @Transactional(readOnly
= false)
231 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
233 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
234 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
235 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
237 //check synonym is not homotypic
238 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
239 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
240 throw new HomotypicalGroupChangeException(message
);
243 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
245 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
246 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
248 for (Synonym heteroSynonym
: heteroSynonyms
){
249 if (synonym
.equals(heteroSynonym
)){
250 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
252 //move synonyms in same homotypic group to new accepted taxon
253 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
257 //synonym.getName().removeTaxonBase(synonym);
258 //TODO correct delete handling still needs to be implemented / checked
260 // deleteSynonym(synonym, taxon, false);
263 this.delete(synonym
);
265 } catch (Exception e
) {
266 logger
.info("Can't delete old synonym from database");
270 return newAcceptedTaxon
;
274 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
276 // Get name from synonym
277 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
279 // remove synonym from taxon
280 toTaxon
.removeSynonym(synonym
);
282 // Create a taxon with synonym name
283 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
285 // Add taxon relation
286 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
288 // since we are swapping names, we have to detach the name from the synonym completely.
289 // Otherwise the synonym will still be in the list of typified names.
290 synonym
.getName().removeTaxonBase(synonym
);
297 * @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)
299 @Transactional(readOnly
= false)
301 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
302 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
304 TaxonNameBase synonymName
= synonym
.getName();
305 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
309 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
310 newHomotypicalGroup
.addTypifiedName(synonymName
);
312 //remove existing basionym relationships
313 synonymName
.removeBasionyms();
315 //add basionym relationship
316 if (setBasionymRelationIfApplicable
){
317 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
318 for (TaxonNameBase basionym
: basionyms
){
319 synonymName
.addBasionym(basionym
);
323 //set synonym relationship correctly
324 // SynonymRelationship relToTaxon = null;
325 boolean relToTargetTaxonExists
= false;
326 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
327 for (SynonymRelationship rel
: existingRelations
){
328 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
329 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
330 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
331 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
332 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
333 rel
.setType(newRelationType
);
334 //TODO handle citation and microCitation
337 relToTargetTaxonExists
= true;
339 if (removeFromOtherTaxa
){
340 acceptedTaxon
.removeSynonym(synonym
, false);
346 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
347 Taxon acceptedTaxon
= targetTaxon
;
348 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
349 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
350 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
351 //TODO handle citation and microCitation
352 Reference citation
= null;
353 String microCitation
= null;
354 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
361 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
364 @Transactional(readOnly
= false)
365 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
367 clazz
= TaxonBase
.class;
369 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
373 protected void setDao(ITaxonDao dao
) {
378 * @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)
380 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
381 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
383 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
384 if(numberOfResults
> 0) { // no point checking again
385 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
388 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
392 * @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)
394 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
395 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
397 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
398 if(numberOfResults
> 0) { // no point checking again
399 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
406 * @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)
408 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
409 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
411 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
412 if(numberOfResults
> 0) { // no point checking again
413 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
419 * @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)
421 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
422 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
424 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
425 if(numberOfResults
> 0) { // no point checking again
426 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
428 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
432 * @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)
434 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
435 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
437 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
438 if(numberOfResults
> 0) { // no point checking again
439 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
445 * @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)
447 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
448 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
450 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
451 if(numberOfResults
> 0) { // no point checking again
452 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
454 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
458 * @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)
460 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
461 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
463 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
464 if(numberOfResults
> 0) { // no point checking again
465 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
468 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
472 * @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)
474 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
475 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
477 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
478 if(numberOfResults
> 0) { // no point checking again
479 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
482 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
486 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
488 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
489 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
490 return t
.getHomotypicSynonymsByHomotypicGroup();
494 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
496 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
497 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
498 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
499 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
500 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
501 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
503 return heterotypicSynonymyGroups
;
506 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator
){
508 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
509 // Class<? extends TaxonBase> clazz = null;
510 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
511 // clazz = TaxonBase.class;
512 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
513 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
514 // } else if(configurator.isDoTaxa()) {
515 // clazz = Taxon.class;
516 // //propertyPath = configurator.getTaxonPropertyPath();
517 // } else if (configurator.isDoSynonyms()) {
518 // clazz = Synonym.class;
519 // //propertyPath = configurator.getSynonymPropertyPath();
523 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
528 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
530 public Pager
<IdentifiableEntity
> findTaxaAndNames(ITaxonServiceConfigurator configurator
) {
532 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
533 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
534 List
<TaxonBase
> taxa
= null;
537 long numberTaxaResults
= 0L;
540 List
<String
> propertyPath
= new ArrayList
<String
>();
541 if(configurator
.getTaxonPropertyPath() != null){
542 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
546 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
547 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
549 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
550 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
551 configurator
.getNamedAreas());
554 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
555 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
556 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
557 configurator
.getMatchMode(), configurator
.getNamedAreas(),
558 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
562 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
565 results
.addAll(taxa
);
568 numberOfResults
+= numberTaxaResults
;
570 // Names without taxa
571 if (configurator
.isDoNamesWithoutTaxa()) {
572 int numberNameResults
= 0;
574 List
<?
extends TaxonNameBase
<?
,?
>> names
=
575 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
576 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
577 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
578 if (names
.size() > 0) {
579 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
580 if (taxonName
.getTaxonBases().size() == 0) {
581 results
.add(taxonName
);
585 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
586 numberOfResults
+= numberNameResults
;
590 // Taxa from common names
592 if (configurator
.isDoTaxaByCommonNames()) {
593 taxa
= new ArrayList
<TaxonBase
>();
594 numberTaxaResults
= 0;
595 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
596 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
598 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
599 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
600 for( Object
[] entry
: commonNameResults
) {
601 taxa
.add((TaxonBase
) entry
[0]);
605 results
.addAll(taxa
);
607 numberOfResults
+= numberTaxaResults
;
611 return new DefaultPagerImpl
<IdentifiableEntity
>
612 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
615 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
616 return dao
.getUuidAndTitleCache();
620 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
622 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
623 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
624 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
625 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
626 for (TaxonDescription taxDesc
: descriptions
){
627 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
628 for (DescriptionElementBase descElem
: elements
){
629 for(Media media
: descElem
.getMedia()){
631 //find the best matching representation
632 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
641 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
643 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
644 return this.dao
.findById(listOfIDs
);
648 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
650 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
651 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
655 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
657 public int countAllRelationships() {
658 return this.dao
.countAllRelationships();
665 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
667 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
668 return this.dao
.findIdenticalTaxonNames(propertyPath
);
673 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
676 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
678 config
= new TaxonDeletionConfigurator();
682 if (! config
.isDeleteTaxonNodes()){
683 if (taxon
.getTaxonNodes().size() > 0){
684 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
685 throw new ReferencedObjectUndeletableException(message
);
690 // SynonymRelationShip
691 if (config
.isDeleteSynonymRelations()){
692 boolean removeSynonymNameFromHomotypicalGroup
= false;
693 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
694 Synonym synonym
= synRel
.getSynonym();
695 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
696 if (config
.isDeleteSynonymsIfPossible()){
698 boolean newHomotypicGroupIfNeeded
= true;
699 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
701 deleteSynonymRelationships(synonym
, taxon
);
707 if (! config
.isDeleteTaxonRelationships()){
708 if (taxon
.getTaxonRelations().size() > 0){
709 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.";
710 throw new ReferencedObjectUndeletableException(message
);
716 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
718 for (TaxonDescription desc
: descriptions
){
719 if (config
.isDeleteDescriptions()){
720 //TODO use description delete configurator ?
721 //FIXME check if description is ALWAYS deletable
722 descriptionService
.delete(desc
);
724 if (desc
.getDescribedSpecimenOrObservations().size()>0){
725 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
726 " which also describes specimens or abservations";
727 throw new ReferencedObjectUndeletableException(message
);
733 //check references with only reverse mapping
734 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
735 for (CdmBase referencingObject
: referencingObjects
){
736 //IIdentificationKeys (Media, Polytomous, MultiAccess)
737 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
738 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
739 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
740 throw new ReferencedObjectUndeletableException(message
);
745 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
746 String message
= "Taxon can't be deleted as it is used in polytomous key node";
747 throw new ReferencedObjectUndeletableException(message
);
751 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
752 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
753 throw new ReferencedObjectUndeletableException(message
);
759 if (config
.isDeleteNameIfPossible()){
761 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
762 } catch (ReferencedObjectUndeletableException e
) {
764 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
771 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
773 @Transactional(readOnly
= false)
775 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
776 if (synonym
== null){
779 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
781 //remove synonymRelationship
782 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
786 taxonSet
.addAll(synonym
.getAcceptedTaxa());
788 for (Taxon relatedTaxon
: taxonSet
){
789 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
790 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
792 this.saveOrUpdate(synonym
);
794 //TODO remove name from homotypical group?
796 //remove synonym (if necessary)
797 if (synonym
.getSynonymRelations().isEmpty()){
798 TaxonNameBase
<?
,?
> name
= synonym
.getName();
799 synonym
.setName(null);
802 //remove name if possible (and required)
803 if (name
!= null && removeNameIfPossible
){
805 nameService
.delete(name
, new NameDeletionConfigurator());
806 }catch (DataChangeNoRollbackException ex
){
807 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
815 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
817 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
819 return this.dao
.findIdenticalNamesNew(propertyPath
);
823 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
825 public String
getPhylumName(TaxonNameBase name
){
826 return this.dao
.getPhylumName(name
);
830 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
832 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
833 return dao
.deleteSynonymRelationships(syn
, taxon
);
837 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
839 public long deleteSynonymRelationships(Synonym syn
) {
840 return dao
.deleteSynonymRelationships(syn
, null);
845 * @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)
847 public List
<SynonymRelationship
> listSynonymRelationships(
848 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
849 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
850 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
852 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
853 if(numberOfResults
> 0) { // no point checking again
854 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
860 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
863 public Taxon
findBestMatchingTaxon(String taxonName
) {
864 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
865 config
.setTaxonNameTitle(taxonName
);
866 return findBestMatchingTaxon(config
);
872 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
874 Taxon bestCandidate
= null;
876 // 1. search for acceptet taxa
877 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
878 boolean bestCandidateMatchesSecUuid
= false;
879 boolean bestCandidateIsInClassification
= false;
880 int countEqualCandidates
= 0;
881 for(TaxonBase taxonBaseCandidate
: taxonList
){
882 if(taxonBaseCandidate
instanceof Taxon
){
883 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
884 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
885 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
887 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
888 bestCandidate
= newCanditate
;
889 countEqualCandidates
= 1;
890 bestCandidateMatchesSecUuid
= true;
894 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
895 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
897 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
898 bestCandidate
= newCanditate
;
899 countEqualCandidates
= 1;
900 bestCandidateIsInClassification
= true;
903 if (bestCandidate
== null){
904 bestCandidate
= newCanditate
;
905 countEqualCandidates
= 1;
909 }else{ //not Taxon.class
912 countEqualCandidates
++;
915 if (bestCandidate
!= null){
916 if(countEqualCandidates
> 1){
917 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
918 return bestCandidate
;
920 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
921 return bestCandidate
;
926 // 2. search for synonyms
927 if (config
.isIncludeSynonyms()){
928 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
929 for(TaxonBase taxonBase
: synonymList
){
930 if(taxonBase
instanceof Synonym
){
931 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
932 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
933 if(!acceptetdCandidates
.isEmpty()){
934 bestCandidate
= acceptetdCandidates
.iterator().next();
935 if(acceptetdCandidates
.size() == 1){
936 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
937 return bestCandidate
;
939 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
940 return bestCandidate
;
942 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
948 } catch (Exception e
){
952 return bestCandidate
;
955 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
956 UUID configClassificationUuid
= config
.getClassificationUuid();
957 if (configClassificationUuid
== null){
960 for (TaxonNode node
: taxon
.getTaxonNodes()){
961 UUID classUuid
= node
.getClassification().getUuid();
962 if (configClassificationUuid
.equals(classUuid
)){
969 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
970 UUID configSecUuid
= config
.getSecUuid();
971 if (configSecUuid
== null){
974 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
975 return configSecUuid
.equals(taxonSecUuid
);
979 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
982 public Synonym
findBestMatchingSynonym(String taxonName
) {
983 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
984 if(! synonymList
.isEmpty()){
985 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
986 if(synonymList
.size() == 1){
987 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
990 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
999 * @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)
1002 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1003 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1005 Synonym synonym
= oldSynonymRelation
.getSynonym();
1006 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1007 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1008 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1009 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1010 //set default relationship type
1011 if (newSynonymRelationshipType
== null){
1012 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1014 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1016 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1017 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1018 boolean isSingleInGroup
= !(hgSize
> 1);
1020 if (! isSingleInGroup
){
1021 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1022 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1023 if (isHomotypicToAccepted
){
1024 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.";
1025 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1026 message
= String
.format(message
, homotypicRelatives
);
1027 throw new HomotypicalGroupChangeException(message
);
1029 if (! moveHomotypicGroup
){
1030 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.";
1031 throw new HomotypicalGroupChangeException(message
);
1034 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1036 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1038 SynonymRelationship result
= null;
1039 //move all synonyms to new taxon
1040 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1041 for (Synonym syn
: homotypicSynonyms
){
1042 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1043 for (SynonymRelationship synRelation
: synRelations
){
1044 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1045 Reference
<?
> newReference
= reference
;
1046 if (newReference
== null && keepReference
){
1047 newReference
= synRelation
.getCitation();
1049 String newRefDetail
= referenceDetail
;
1050 if (newRefDetail
== null && keepReference
){
1051 newRefDetail
= synRelation
.getCitationMicroReference();
1053 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1054 fromTaxon
.removeSynonymRelation(synRelation
, false);
1056 //change homotypic group of synonym if relType is 'homotypic'
1057 // if (newRelTypeIsHomotypic){
1058 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1061 if (synRelation
.equals(oldSynonymRelation
)){
1062 result
= newSynRelation
;
1068 saveOrUpdate(newTaxon
);
1069 //Assert that there is a result
1070 if (result
== null){
1071 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1072 throw new IllegalStateException(message
);
1078 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1081 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1082 return dao
.getUuidAndTitleCacheTaxon();
1086 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1089 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1090 return dao
.getUuidAndTitleCacheSynonym();
1094 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1095 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1096 List
<Language
> languages
, Integer pageSize
, Integer pageNumber
,
1097 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1099 Class
<?
extends DescriptionElementBase
> directorySelectClass
= DescriptionElementBase
.class;
1101 directorySelectClass
= clazz
;
1104 StringBuilder luceneQueryTemplate
= new StringBuilder();
1106 luceneQueryTemplate
.append("titleCache:%1$s ");
1108 if(languages
== null || languages
.size() == 0){
1109 luceneQueryTemplate
.append("name:%1$s ");
1111 luceneQueryTemplate
.append("(name:%1$s AND (");
1112 for(Language lang
: languages
){
1113 luceneQueryTemplate
.append(" language.uuid:" + lang
.getUuid().toString());
1115 luceneQueryTemplate
.append("))");
1117 // text field from TextData
1118 appendLocalizedFieldQuery("text", languages
, luceneQueryTemplate
).append(" ");
1119 // state field from CategoricalData
1120 appendLocalizedFieldQuery("states.state.representation", languages
, luceneQueryTemplate
).append(" ");
1121 // state field from CategoricalData
1122 appendLocalizedFieldQuery("states.modifyingText", languages
, luceneQueryTemplate
).append(" ");
1124 // String luceneQueryTemplate = typeSelect + "( titleCache:%1$s OR " + languageSelection + "OR name:%1$s )";
1125 String luceneQuery
= String
.format(luceneQueryTemplate
.toString(), queryString
);
1127 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), directorySelectClass
);
1128 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(luceneQuery
, clazz
);
1129 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSetFromIds(luceneSearch
, topDocsResultSet
, dao
, "inDescription.taxon.id");
1131 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
1136 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseFieldBridge}
1137 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1138 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1140 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseFieldBridge}
1141 * or {@link MultilanguageTextFieldBridge }
1142 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1143 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1144 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1146 * TODO move to utiliy class !!!!!!!!
1148 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1150 if(stringBuilder
== null){
1151 stringBuilder
= new StringBuilder();
1153 if(languages
== null || languages
.size() == 0){
1154 stringBuilder
.append(name
+ ".ALL:%1$s ");
1156 for(Language lang
: languages
){
1157 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":%1$s ");
1160 return stringBuilder
;
1163 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1164 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1165 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1167 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1170 UUID uuid
= taxon
.getName().getUuid();
1171 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1172 String epithetOfTaxon
= null;
1173 String infragenericEpithetOfTaxon
= null;
1174 String infraspecificEpithetOfTaxon
= null;
1175 if (taxonName
.isSpecies()){
1176 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1177 } else if (taxonName
.isInfraGeneric()){
1178 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1179 } else if (taxonName
.isInfraSpecific()){
1180 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1182 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1183 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1184 List
<String
> taxonNames
= new ArrayList
<String
>();
1186 for (TaxonNode node
: nodes
){
1187 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1188 // List<String> synonymsEpithet = new ArrayList<String>();
1190 if (node
.getClassification().equals(classification
)){
1191 if (!node
.isTopmostNode()){
1192 TaxonNode parent
= (TaxonNode
)node
.getParent();
1193 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1194 TaxonNameBase parentName
= parent
.getTaxon().getName();
1195 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1196 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1197 Rank rankOfTaxon
= taxonName
.getRank();
1200 //create inferred synonyms for species, subspecies
1201 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1203 Synonym inferredEpithet
= null;
1204 Synonym inferredGenus
= null;
1205 Synonym potentialCombination
= null;
1207 List
<String
> propertyPaths
= new ArrayList
<String
>();
1208 propertyPaths
.add("synonym");
1209 propertyPaths
.add("synonym.name");
1210 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1211 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1213 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1214 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1216 List
<TaxonRelationship
> taxonRelListParent
= null;
1217 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1218 if (doWithMisappliedNames
){
1219 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1220 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1224 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1225 Set
<String
> genusNames
= new HashSet
<String
>();
1227 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1228 Synonym syn
= synonymRelationOfParent
.getSynonym();
1230 inferredEpithet
= createInferredEpithets(taxon
,
1231 zooHashMap
, taxonName
, epithetOfTaxon
,
1232 infragenericEpithetOfTaxon
,
1233 infraspecificEpithetOfTaxon
,
1234 taxonNames
, parentName
,
1238 inferredSynonyms
.add(inferredEpithet
);
1239 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1240 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1243 if (doWithMisappliedNames
){
1245 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1246 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1248 inferredEpithet
= createInferredEpithets(taxon
,
1249 zooHashMap
, taxonName
, epithetOfTaxon
,
1250 infragenericEpithetOfTaxon
,
1251 infraspecificEpithetOfTaxon
,
1252 taxonNames
, parentName
,
1255 inferredSynonyms
.add(inferredEpithet
);
1256 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1257 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1261 if (!taxonNames
.isEmpty()){
1262 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1263 ZoologicalName name
;
1264 if (!synNotInCDM
.isEmpty()){
1265 inferredSynonymsToBeRemoved
.clear();
1267 for (Synonym syn
:inferredSynonyms
){
1268 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1269 if (!synNotInCDM
.contains(name
.getNameCache())){
1270 inferredSynonymsToBeRemoved
.add(syn
);
1274 // Remove identified Synonyms from inferredSynonyms
1275 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1276 inferredSynonyms
.remove(synonym
);
1281 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1284 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1285 TaxonNameBase synName
;
1286 ZoologicalName inferredSynName
;
1288 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1289 inferredGenus
= createInferredGenus(taxon
,
1290 zooHashMap
, taxonName
, epithetOfTaxon
,
1291 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1293 inferredSynonyms
.add(inferredGenus
);
1294 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1295 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1300 if (doWithMisappliedNames
){
1302 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1303 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1304 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1306 inferredSynonyms
.add(inferredGenus
);
1307 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1308 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1313 if (!taxonNames
.isEmpty()){
1314 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1315 ZoologicalName name
;
1316 if (!synNotInCDM
.isEmpty()){
1317 inferredSynonymsToBeRemoved
.clear();
1319 for (Synonym syn
:inferredSynonyms
){
1320 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1321 if (!synNotInCDM
.contains(name
.getNameCache())){
1322 inferredSynonymsToBeRemoved
.add(syn
);
1326 // Remove identified Synonyms from inferredSynonyms
1327 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1328 inferredSynonyms
.remove(synonym
);
1333 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1335 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1336 ZoologicalName inferredSynName
;
1337 //for all synonyms of the parent...
1338 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1339 TaxonNameBase synName
;
1340 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1341 synName
= synParent
.getName();
1343 HibernateProxyHelper
.deproxy(synParent
);
1345 // Set the sourceReference
1346 sourceReference
= synParent
.getSec();
1348 // Determine the idInSource
1349 String idInSourceParent
= getIdInSource(synParent
);
1351 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1352 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1353 String synParentInfragenericName
= null;
1354 String synParentSpecificEpithet
= null;
1356 if (parentSynZooName
.isInfraGeneric()){
1357 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1359 if (parentSynZooName
.isSpecies()){
1360 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1363 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1364 synonymsGenus.put(synGenusName, idInSource);
1367 //for all synonyms of the taxon
1369 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1371 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1372 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1373 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1375 synParentInfragenericName
,
1376 synParentSpecificEpithet
, syn
, zooHashMap
);
1378 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1379 inferredSynonyms
.add(potentialCombination
);
1380 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1381 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1388 if (doWithMisappliedNames
){
1390 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1392 TaxonNameBase misappliedParentName
;
1394 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1395 misappliedParentName
= misappliedParent
.getName();
1397 HibernateProxyHelper
.deproxy(misappliedParent
);
1399 // Set the sourceReference
1400 sourceReference
= misappliedParent
.getSec();
1402 // Determine the idInSource
1403 String idInSourceParent
= getIdInSource(misappliedParent
);
1405 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1406 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1407 String synParentInfragenericName
= null;
1408 String synParentSpecificEpithet
= null;
1410 if (parentSynZooName
.isInfraGeneric()){
1411 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1413 if (parentSynZooName
.isSpecies()){
1414 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1418 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1419 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1420 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1421 potentialCombination
= createPotentialCombination(
1422 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1424 synParentInfragenericName
,
1425 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1428 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1429 inferredSynonyms
.add(potentialCombination
);
1430 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1431 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1436 if (!taxonNames
.isEmpty()){
1437 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1438 ZoologicalName name
;
1439 if (!synNotInCDM
.isEmpty()){
1440 inferredSynonymsToBeRemoved
.clear();
1441 for (Synonym syn
:inferredSynonyms
){
1443 name
= (ZoologicalName
) syn
.getName();
1444 }catch (ClassCastException e
){
1445 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1447 if (!synNotInCDM
.contains(name
.getNameCache())){
1448 inferredSynonymsToBeRemoved
.add(syn
);
1451 // Remove identified Synonyms from inferredSynonyms
1452 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1453 inferredSynonyms
.remove(synonym
);
1459 logger
.info("The synonymrelationship type is not defined.");
1460 return inferredSynonyms
;
1467 return inferredSynonyms
;
1470 private Synonym
createPotentialCombination(String idInSourceParent
,
1471 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1472 String synParentInfragenericName
, String synParentSpecificEpithet
,
1473 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1474 Synonym potentialCombination
;
1475 Reference sourceReference
;
1476 ZoologicalName inferredSynName
;
1477 HibernateProxyHelper
.deproxy(syn
);
1479 // Set sourceReference
1480 sourceReference
= syn
.getSec();
1483 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1485 String synTaxonInfraSpecificName
= null;
1487 if (parentSynZooName
.isSpecies()){
1488 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1491 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1492 synonymsEpithet.add(epithetName);
1495 //create potential combinations...
1496 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1498 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1499 if (zooSynName
.isSpecies()){
1500 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1501 if (parentSynZooName
.isInfraGeneric()){
1502 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1505 if (zooSynName
.isInfraSpecific()){
1506 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1507 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1509 if (parentSynZooName
.isInfraGeneric()){
1510 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1514 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1516 // Set the sourceReference
1517 potentialCombination
.setSec(sourceReference
);
1520 // Determine the idInSource
1521 String idInSourceSyn
= getIdInSource(syn
);
1523 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1524 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1525 inferredSynName
.addSource(originalSource
);
1526 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1527 potentialCombination
.addSource(originalSource
);
1530 inferredSynName
.generateTitle();
1532 return potentialCombination
;
1535 private Synonym
createInferredGenus(Taxon taxon
,
1536 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1537 String epithetOfTaxon
, String genusOfTaxon
,
1538 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1541 Synonym inferredGenus
;
1542 TaxonNameBase synName
;
1543 ZoologicalName inferredSynName
;
1544 synName
=syn
.getName();
1545 HibernateProxyHelper
.deproxy(syn
);
1547 // Determine the idInSource
1548 String idInSourceSyn
= getIdInSource(syn
);
1549 String idInSourceTaxon
= getIdInSource(taxon
);
1550 // Determine the sourceReference
1551 Reference sourceReference
= syn
.getSec();
1553 synName
= syn
.getName();
1554 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1555 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1556 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1557 synonymsEpithet.add(synSpeciesEpithetName);
1560 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1561 //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...
1564 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1565 if (zooParentName
.isInfraGeneric()){
1566 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1569 if (taxonName
.isSpecies()){
1570 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1572 if (taxonName
.isInfraSpecific()){
1573 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1574 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1578 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1580 // Set the sourceReference
1581 inferredGenus
.setSec(sourceReference
);
1583 // Add the original source
1584 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1585 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1586 inferredGenus
.addSource(originalSource
);
1588 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1589 inferredSynName
.addSource(originalSource
);
1593 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1595 inferredSynName
.generateTitle();
1598 return inferredGenus
;
1601 private Synonym
createInferredEpithets(Taxon taxon
,
1602 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1603 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1604 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1605 TaxonNameBase parentName
, TaxonBase syn
) {
1607 Synonym inferredEpithet
;
1608 TaxonNameBase synName
;
1609 ZoologicalName inferredSynName
;
1610 HibernateProxyHelper
.deproxy(syn
);
1612 // Determine the idInSource
1613 String idInSourceSyn
= getIdInSource(syn
);
1614 String idInSourceTaxon
= getIdInSource(taxon
);
1615 // Determine the sourceReference
1616 Reference sourceReference
= syn
.getSec();
1618 synName
= syn
.getName();
1619 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1620 String synGenusName
= zooSynName
.getGenusOrUninomial();
1621 String synInfraGenericEpithet
= null;
1622 String synSpecificEpithet
= null;
1624 if (zooSynName
.getInfraGenericEpithet() != null){
1625 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1628 if (zooSynName
.isInfraSpecific()){
1629 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1632 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1633 synonymsGenus.put(synGenusName, idInSource);
1636 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1638 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1639 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1640 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1642 inferredSynName
.setGenusOrUninomial(synGenusName
);
1644 if (parentName
.isInfraGeneric()){
1645 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1647 if (taxonName
.isSpecies()){
1648 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1649 }else if (taxonName
.isInfraSpecific()){
1650 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1651 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1654 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1656 // Set the sourceReference
1657 inferredEpithet
.setSec(sourceReference
);
1659 /* Add the original source
1660 if (idInSource != null) {
1661 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1664 Reference citation = getCitation(syn);
1665 if (citation != null) {
1666 originalSource.setCitation(citation);
1667 inferredEpithet.addSource(originalSource);
1670 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1672 IdentifiableSource originalSource
;
1673 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1675 inferredEpithet
.addSource(originalSource
);
1677 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1679 inferredSynName
.addSource(originalSource
);
1683 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1685 inferredSynName
.generateTitle();
1686 return inferredEpithet
;
1690 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1691 * Very likely only useful for createInferredSynonyms().
1696 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1697 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1698 if (taxonName
== null) {
1699 taxonName
= zooHashMap
.get(uuid
);
1705 * Returns the idInSource for a given Synonym.
1708 private String
getIdInSource(TaxonBase taxonBase
) {
1709 String idInSource
= null;
1710 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1711 if (sources
.size() == 1) {
1712 IdentifiableSource source
= sources
.iterator().next();
1713 if (source
!= null) {
1714 idInSource
= source
.getIdInSource();
1716 } else if (sources
.size() > 1) {
1719 for (IdentifiableSource source
: sources
) {
1720 idInSource
+= source
.getIdInSource();
1721 if (count
< sources
.size()) {
1733 * Returns the citation for a given Synonym.
1736 private Reference
getCitation(Synonym syn
) {
1737 Reference citation
= null;
1738 Set
<IdentifiableSource
> sources
= syn
.getSources();
1739 if (sources
.size() == 1) {
1740 IdentifiableSource source
= sources
.iterator().next();
1741 if (source
!= null) {
1742 citation
= source
.getCitation();
1744 } else if (sources
.size() > 1) {
1745 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1751 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1752 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1754 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1755 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1756 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1758 return inferredSynonyms
;