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
.Query
;
25 import org
.apache
.lucene
.search
.SortField
;
26 import org
.apache
.lucene
.search
.TopDocs
;
27 import org
.hibernate
.criterion
.Criterion
;
28 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
29 import org
.springframework
.stereotype
.Service
;
30 import org
.springframework
.transaction
.annotation
.Propagation
;
31 import org
.springframework
.transaction
.annotation
.Transactional
;
33 import eu
.etaxonomy
.cdm
.api
.service
.config
.ITaxonServiceConfigurator
;
34 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
35 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
36 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
37 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
38 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
39 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
40 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
41 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
42 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
43 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
44 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
45 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultHighligther
;
47 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
48 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
49 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
50 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
51 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
52 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
53 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
54 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
55 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
56 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
57 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
58 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
59 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
60 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
61 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
62 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
63 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
64 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
65 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
66 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
67 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
68 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
69 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
70 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
71 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
72 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
73 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
74 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
75 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
76 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
77 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
78 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
79 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
80 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
81 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
82 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
83 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
84 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
85 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
86 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
87 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
88 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
89 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
90 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
91 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
95 * @author a.kohlbecker
100 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
101 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
102 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
104 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
106 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
108 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
112 private ITaxonNameDao nameDao
;
115 private INameService nameService
;
118 private ICdmGenericDao genericDao
;
121 private IDescriptionService descriptionService
;
124 private IOrderedTermVocabularyDao orderedVocabularyDao
;
129 public TaxonServiceImpl(){
130 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
134 * FIXME Candidate for harmonization
135 * rename searchByName ?
137 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
138 return dao
.getTaxaByName(name
, sec
);
142 * FIXME Candidate for harmonization
143 * list(Synonym.class, ...)
145 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
147 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
148 return dao
.getAllSynonyms(limit
, start
);
152 * FIXME Candidate for harmonization
153 * list(Taxon.class, ...)
155 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
157 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
158 return dao
.getAllTaxa(limit
, start
);
162 * FIXME Candidate for harmonization
163 * merge with getRootTaxa(Reference sec, ..., ...)
165 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
167 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
168 if (cdmFetch
== null){
169 cdmFetch
= CdmFetch
.NO_FETCH();
171 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
176 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
178 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
179 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
183 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
185 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
186 return dao
.getAllRelationships(limit
, start
);
190 * FIXME Candidate for harmonization
191 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
194 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
196 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
197 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
198 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
199 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
200 return taxonRelTypeVocabulary
;
207 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
209 @Transactional(readOnly
= false)
210 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
212 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
213 synonymName
.removeTaxonBase(synonym
);
214 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
215 taxonName
.removeTaxonBase(acceptedTaxon
);
217 synonym
.setName(taxonName
);
218 acceptedTaxon
.setName(synonymName
);
220 // the accepted taxon needs a new uuid because the concept has changed
221 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
222 //acceptedTaxon.setUuid(UUID.randomUUID());
227 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
229 //TODO correct delete handling still needs to be implemented / checked
231 @Transactional(readOnly
= false)
232 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
234 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
235 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
236 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
238 //check synonym is not homotypic
239 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
240 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
241 throw new HomotypicalGroupChangeException(message
);
244 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
246 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
247 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
249 for (Synonym heteroSynonym
: heteroSynonyms
){
250 if (synonym
.equals(heteroSynonym
)){
251 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
253 //move synonyms in same homotypic group to new accepted taxon
254 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
258 //synonym.getName().removeTaxonBase(synonym);
259 //TODO correct delete handling still needs to be implemented / checked
261 // deleteSynonym(synonym, taxon, false);
264 this.delete(synonym
);
266 } catch (Exception e
) {
267 logger
.info("Can't delete old synonym from database");
271 return newAcceptedTaxon
;
275 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
277 // Get name from synonym
278 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
280 // remove synonym from taxon
281 toTaxon
.removeSynonym(synonym
);
283 // Create a taxon with synonym name
284 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
286 // Add taxon relation
287 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
289 // since we are swapping names, we have to detach the name from the synonym completely.
290 // Otherwise the synonym will still be in the list of typified names.
291 synonym
.getName().removeTaxonBase(synonym
);
298 * @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)
300 @Transactional(readOnly
= false)
302 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
303 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
305 TaxonNameBase synonymName
= synonym
.getName();
306 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
310 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
311 newHomotypicalGroup
.addTypifiedName(synonymName
);
313 //remove existing basionym relationships
314 synonymName
.removeBasionyms();
316 //add basionym relationship
317 if (setBasionymRelationIfApplicable
){
318 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
319 for (TaxonNameBase basionym
: basionyms
){
320 synonymName
.addBasionym(basionym
);
324 //set synonym relationship correctly
325 // SynonymRelationship relToTaxon = null;
326 boolean relToTargetTaxonExists
= false;
327 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
328 for (SynonymRelationship rel
: existingRelations
){
329 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
330 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
331 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
332 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
333 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
334 rel
.setType(newRelationType
);
335 //TODO handle citation and microCitation
338 relToTargetTaxonExists
= true;
340 if (removeFromOtherTaxa
){
341 acceptedTaxon
.removeSynonym(synonym
, false);
347 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
348 Taxon acceptedTaxon
= targetTaxon
;
349 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
350 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
351 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
352 //TODO handle citation and microCitation
353 Reference citation
= null;
354 String microCitation
= null;
355 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
362 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
365 @Transactional(readOnly
= false)
366 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
368 clazz
= TaxonBase
.class;
370 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
374 protected void setDao(ITaxonDao dao
) {
379 * @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)
381 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
382 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
384 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
385 if(numberOfResults
> 0) { // no point checking again
386 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
389 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
393 * @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)
395 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
396 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
398 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
399 if(numberOfResults
> 0) { // no point checking again
400 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
407 * @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)
409 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
410 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
412 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
413 if(numberOfResults
> 0) { // no point checking again
414 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
420 * @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)
422 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
423 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
425 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
426 if(numberOfResults
> 0) { // no point checking again
427 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
429 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
433 * @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)
435 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
436 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
438 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
439 if(numberOfResults
> 0) { // no point checking again
440 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
446 * @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)
448 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
449 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
451 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
452 if(numberOfResults
> 0) { // no point checking again
453 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
455 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
459 * @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)
461 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
462 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
464 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
465 if(numberOfResults
> 0) { // no point checking again
466 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
469 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
473 * @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)
475 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
476 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
478 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
479 if(numberOfResults
> 0) { // no point checking again
480 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
483 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
487 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
489 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
490 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
491 return t
.getHomotypicSynonymsByHomotypicGroup();
495 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
497 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
498 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
499 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
500 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
501 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
502 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
504 return heterotypicSynonymyGroups
;
507 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator
){
509 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
510 // Class<? extends TaxonBase> clazz = null;
511 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
512 // clazz = TaxonBase.class;
513 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
514 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
515 // } else if(configurator.isDoTaxa()) {
516 // clazz = Taxon.class;
517 // //propertyPath = configurator.getTaxonPropertyPath();
518 // } else if (configurator.isDoSynonyms()) {
519 // clazz = Synonym.class;
520 // //propertyPath = configurator.getSynonymPropertyPath();
524 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
529 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
531 public Pager
<IdentifiableEntity
> findTaxaAndNames(ITaxonServiceConfigurator configurator
) {
533 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
534 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
535 List
<TaxonBase
> taxa
= null;
538 long numberTaxaResults
= 0L;
541 List
<String
> propertyPath
= new ArrayList
<String
>();
542 if(configurator
.getTaxonPropertyPath() != null){
543 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
547 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
548 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
550 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
551 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
552 configurator
.getNamedAreas());
555 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
556 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
557 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
558 configurator
.getMatchMode(), configurator
.getNamedAreas(),
559 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
563 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
566 results
.addAll(taxa
);
569 numberOfResults
+= numberTaxaResults
;
571 // Names without taxa
572 if (configurator
.isDoNamesWithoutTaxa()) {
573 int numberNameResults
= 0;
575 List
<?
extends TaxonNameBase
<?
,?
>> names
=
576 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
577 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
578 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
579 if (names
.size() > 0) {
580 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
581 if (taxonName
.getTaxonBases().size() == 0) {
582 results
.add(taxonName
);
586 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
587 numberOfResults
+= numberNameResults
;
591 // Taxa from common names
593 if (configurator
.isDoTaxaByCommonNames()) {
594 taxa
= new ArrayList
<TaxonBase
>();
595 numberTaxaResults
= 0;
596 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
597 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
599 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
600 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
601 for( Object
[] entry
: commonNameResults
) {
602 taxa
.add((TaxonBase
) entry
[0]);
606 results
.addAll(taxa
);
608 numberOfResults
+= numberTaxaResults
;
612 return new DefaultPagerImpl
<IdentifiableEntity
>
613 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
616 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
617 return dao
.getUuidAndTitleCache();
621 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
623 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
624 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
625 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
626 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
627 for (TaxonDescription taxDesc
: descriptions
){
628 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
629 for (DescriptionElementBase descElem
: elements
){
630 for(Media media
: descElem
.getMedia()){
632 //find the best matching representation
633 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
642 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
644 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
645 return this.dao
.findById(listOfIDs
);
649 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
651 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
652 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
656 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
658 public int countAllRelationships() {
659 return this.dao
.countAllRelationships();
666 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
668 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
669 return this.dao
.findIdenticalTaxonNames(propertyPath
);
674 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
677 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
679 config
= new TaxonDeletionConfigurator();
683 if (! config
.isDeleteTaxonNodes()){
684 if (taxon
.getTaxonNodes().size() > 0){
685 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
686 throw new ReferencedObjectUndeletableException(message
);
691 // SynonymRelationShip
692 if (config
.isDeleteSynonymRelations()){
693 boolean removeSynonymNameFromHomotypicalGroup
= false;
694 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
695 Synonym synonym
= synRel
.getSynonym();
696 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
697 if (config
.isDeleteSynonymsIfPossible()){
699 boolean newHomotypicGroupIfNeeded
= true;
700 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
702 deleteSynonymRelationships(synonym
, taxon
);
708 if (! config
.isDeleteTaxonRelationships()){
709 if (taxon
.getTaxonRelations().size() > 0){
710 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.";
711 throw new ReferencedObjectUndeletableException(message
);
717 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
719 for (TaxonDescription desc
: descriptions
){
720 if (config
.isDeleteDescriptions()){
721 //TODO use description delete configurator ?
722 //FIXME check if description is ALWAYS deletable
723 descriptionService
.delete(desc
);
725 if (desc
.getDescribedSpecimenOrObservations().size()>0){
726 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
727 " which also describes specimens or abservations";
728 throw new ReferencedObjectUndeletableException(message
);
734 //check references with only reverse mapping
735 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
736 for (CdmBase referencingObject
: referencingObjects
){
737 //IIdentificationKeys (Media, Polytomous, MultiAccess)
738 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
739 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
740 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
741 throw new ReferencedObjectUndeletableException(message
);
746 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
747 String message
= "Taxon can't be deleted as it is used in polytomous key node";
748 throw new ReferencedObjectUndeletableException(message
);
752 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
753 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
754 throw new ReferencedObjectUndeletableException(message
);
760 if (config
.isDeleteNameIfPossible()){
762 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
763 } catch (ReferencedObjectUndeletableException e
) {
765 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
772 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
774 @Transactional(readOnly
= false)
776 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
777 if (synonym
== null){
780 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
782 //remove synonymRelationship
783 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
787 taxonSet
.addAll(synonym
.getAcceptedTaxa());
789 for (Taxon relatedTaxon
: taxonSet
){
790 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
791 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
793 this.saveOrUpdate(synonym
);
795 //TODO remove name from homotypical group?
797 //remove synonym (if necessary)
798 if (synonym
.getSynonymRelations().isEmpty()){
799 TaxonNameBase
<?
,?
> name
= synonym
.getName();
800 synonym
.setName(null);
803 //remove name if possible (and required)
804 if (name
!= null && removeNameIfPossible
){
806 nameService
.delete(name
, new NameDeletionConfigurator());
807 }catch (DataChangeNoRollbackException ex
){
808 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
816 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
818 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
820 return this.dao
.findIdenticalNamesNew(propertyPath
);
824 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
826 public String
getPhylumName(TaxonNameBase name
){
827 return this.dao
.getPhylumName(name
);
831 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
833 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
834 return dao
.deleteSynonymRelationships(syn
, taxon
);
838 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
840 public long deleteSynonymRelationships(Synonym syn
) {
841 return dao
.deleteSynonymRelationships(syn
, null);
846 * @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)
848 public List
<SynonymRelationship
> listSynonymRelationships(
849 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
850 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
851 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
853 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
854 if(numberOfResults
> 0) { // no point checking again
855 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
861 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
864 public Taxon
findBestMatchingTaxon(String taxonName
) {
865 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
866 config
.setTaxonNameTitle(taxonName
);
867 return findBestMatchingTaxon(config
);
873 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
875 Taxon bestCandidate
= null;
877 // 1. search for acceptet taxa
878 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
879 boolean bestCandidateMatchesSecUuid
= false;
880 boolean bestCandidateIsInClassification
= false;
881 int countEqualCandidates
= 0;
882 for(TaxonBase taxonBaseCandidate
: taxonList
){
883 if(taxonBaseCandidate
instanceof Taxon
){
884 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
885 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
886 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
888 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
889 bestCandidate
= newCanditate
;
890 countEqualCandidates
= 1;
891 bestCandidateMatchesSecUuid
= true;
895 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
896 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
898 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
899 bestCandidate
= newCanditate
;
900 countEqualCandidates
= 1;
901 bestCandidateIsInClassification
= true;
904 if (bestCandidate
== null){
905 bestCandidate
= newCanditate
;
906 countEqualCandidates
= 1;
910 }else{ //not Taxon.class
913 countEqualCandidates
++;
916 if (bestCandidate
!= null){
917 if(countEqualCandidates
> 1){
918 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
919 return bestCandidate
;
921 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
922 return bestCandidate
;
927 // 2. search for synonyms
928 if (config
.isIncludeSynonyms()){
929 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
930 for(TaxonBase taxonBase
: synonymList
){
931 if(taxonBase
instanceof Synonym
){
932 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
933 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
934 if(!acceptetdCandidates
.isEmpty()){
935 bestCandidate
= acceptetdCandidates
.iterator().next();
936 if(acceptetdCandidates
.size() == 1){
937 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
938 return bestCandidate
;
940 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
941 return bestCandidate
;
943 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
949 } catch (Exception e
){
953 return bestCandidate
;
956 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
957 UUID configClassificationUuid
= config
.getClassificationUuid();
958 if (configClassificationUuid
== null){
961 for (TaxonNode node
: taxon
.getTaxonNodes()){
962 UUID classUuid
= node
.getClassification().getUuid();
963 if (configClassificationUuid
.equals(classUuid
)){
970 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
971 UUID configSecUuid
= config
.getSecUuid();
972 if (configSecUuid
== null){
975 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
976 return configSecUuid
.equals(taxonSecUuid
);
980 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
983 public Synonym
findBestMatchingSynonym(String taxonName
) {
984 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
985 if(! synonymList
.isEmpty()){
986 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
987 if(synonymList
.size() == 1){
988 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
991 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1000 * @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)
1003 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1004 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1006 Synonym synonym
= oldSynonymRelation
.getSynonym();
1007 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1008 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1009 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1010 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1011 //set default relationship type
1012 if (newSynonymRelationshipType
== null){
1013 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1015 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1017 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1018 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1019 boolean isSingleInGroup
= !(hgSize
> 1);
1021 if (! isSingleInGroup
){
1022 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1023 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1024 if (isHomotypicToAccepted
){
1025 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.";
1026 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1027 message
= String
.format(message
, homotypicRelatives
);
1028 throw new HomotypicalGroupChangeException(message
);
1030 if (! moveHomotypicGroup
){
1031 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.";
1032 throw new HomotypicalGroupChangeException(message
);
1035 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1037 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1039 SynonymRelationship result
= null;
1040 //move all synonyms to new taxon
1041 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1042 for (Synonym syn
: homotypicSynonyms
){
1043 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1044 for (SynonymRelationship synRelation
: synRelations
){
1045 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1046 Reference
<?
> newReference
= reference
;
1047 if (newReference
== null && keepReference
){
1048 newReference
= synRelation
.getCitation();
1050 String newRefDetail
= referenceDetail
;
1051 if (newRefDetail
== null && keepReference
){
1052 newRefDetail
= synRelation
.getCitationMicroReference();
1054 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1055 fromTaxon
.removeSynonymRelation(synRelation
, false);
1057 //change homotypic group of synonym if relType is 'homotypic'
1058 // if (newRelTypeIsHomotypic){
1059 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1062 if (synRelation
.equals(oldSynonymRelation
)){
1063 result
= newSynRelation
;
1069 saveOrUpdate(newTaxon
);
1070 //Assert that there is a result
1071 if (result
== null){
1072 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1073 throw new IllegalStateException(message
);
1079 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1082 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1083 return dao
.getUuidAndTitleCacheTaxon();
1087 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1090 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1091 return dao
.getUuidAndTitleCacheSynonym();
1095 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1096 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1097 Classification classification
, List
<Language
> languages
, boolean highlightFragments
,
1098 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1100 Class
<?
extends DescriptionElementBase
> directorySelectClass
= DescriptionElementBase
.class;
1102 directorySelectClass
= clazz
;
1105 Set
<String
> freetextFields
= new HashSet
<String
>();
1106 // ---- search criteria
1107 freetextFields
.add("titleCache");
1108 StringBuilder luceneQueryTemplate
= new StringBuilder();
1109 luceneQueryTemplate
.append("+(");
1110 luceneQueryTemplate
.append("titleCache:%1$s ");
1112 freetextFields
.add("name");
1113 if(languages
== null || languages
.size() == 0){
1114 luceneQueryTemplate
.append("name:%1$s ");
1116 luceneQueryTemplate
.append("(+name:%1$s ");
1117 for(Language lang
: languages
){
1118 luceneQueryTemplate
.append(" +language.uuid:" + lang
.getUuid().toString());
1120 luceneQueryTemplate
.append(")");
1122 // text field from TextData
1123 freetextFields
.add("text.ALL");
1124 appendLocalizedFieldQuery("text", languages
, luceneQueryTemplate
).append(" ");
1125 // state field from CategoricalData
1126 freetextFields
.add("states.state.representation.ALL");
1127 appendLocalizedFieldQuery("states.state.representation", languages
, luceneQueryTemplate
).append(" ");
1128 // state field from CategoricalData
1129 freetextFields
.add("states.modifyingText.ALL");
1130 appendLocalizedFieldQuery("states.modifyingText", languages
, luceneQueryTemplate
).append(" ");
1131 luceneQueryTemplate
.append(") ");
1133 if(classification
!= null){
1134 luceneQueryTemplate
.append("+inDescription.taxon.taxonNodes.classification.id:").append(classification
.getId()).append(" ");
1136 // the description must be associated with a taxon
1137 // TODO open range queries [0 TO *] not working in the current version of lucene (https://issues.apache.org/jira/browse/LUCENE-995)
1138 // so we are using integer maximum as workaround
1139 luceneQueryTemplate
.append("+inDescription.taxon.id:[0 TO " + Integer
.MAX_VALUE
+ "] ");
1141 String luceneQueryStr
= String
.format(luceneQueryTemplate
.toString(), queryString
);
1144 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", false)};
1146 // ---- execute criteria
1147 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), directorySelectClass
);
1149 Query luceneQuery
= luceneSearch
.parse(luceneQueryStr
);
1150 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(luceneQuery
, clazz
, pageSize
, pageNumber
, sortFields
);
1152 String
[] highlightFields
= null;
1153 if(highlightFragments
){
1154 highlightFields
= freetextFields
.toArray(new String
[freetextFields
.size()]);
1157 // initialize taxa, thighlight matches ....
1158 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneQuery
);
1159 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1160 topDocsResultSet
, highlightFields
, dao
, "inDescription.taxon.id", propertyPaths
);
1162 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
1167 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1168 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1169 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1171 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1172 * or {@link MultilanguageTextFieldBridge }
1173 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1174 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1175 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1177 * TODO move to utiliy class !!!!!!!!
1179 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1181 if(stringBuilder
== null){
1182 stringBuilder
= new StringBuilder();
1184 if(languages
== null || languages
.size() == 0){
1185 stringBuilder
.append(name
+ ".ALL:%1$s ");
1187 for(Language lang
: languages
){
1188 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":%1$s ");
1191 return stringBuilder
;
1194 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1195 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1196 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1198 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1201 UUID uuid
= taxon
.getName().getUuid();
1202 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1203 String epithetOfTaxon
= null;
1204 String infragenericEpithetOfTaxon
= null;
1205 String infraspecificEpithetOfTaxon
= null;
1206 if (taxonName
.isSpecies()){
1207 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1208 } else if (taxonName
.isInfraGeneric()){
1209 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1210 } else if (taxonName
.isInfraSpecific()){
1211 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1213 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1214 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1215 List
<String
> taxonNames
= new ArrayList
<String
>();
1217 for (TaxonNode node
: nodes
){
1218 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1219 // List<String> synonymsEpithet = new ArrayList<String>();
1221 if (node
.getClassification().equals(classification
)){
1222 if (!node
.isTopmostNode()){
1223 TaxonNode parent
= (TaxonNode
)node
.getParent();
1224 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1225 TaxonNameBase parentName
= parent
.getTaxon().getName();
1226 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1227 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1228 Rank rankOfTaxon
= taxonName
.getRank();
1231 //create inferred synonyms for species, subspecies
1232 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1234 Synonym inferredEpithet
= null;
1235 Synonym inferredGenus
= null;
1236 Synonym potentialCombination
= null;
1238 List
<String
> propertyPaths
= new ArrayList
<String
>();
1239 propertyPaths
.add("synonym");
1240 propertyPaths
.add("synonym.name");
1241 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1242 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1244 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1245 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1247 List
<TaxonRelationship
> taxonRelListParent
= null;
1248 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1249 if (doWithMisappliedNames
){
1250 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1251 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1255 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1256 Set
<String
> genusNames
= new HashSet
<String
>();
1258 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1259 Synonym syn
= synonymRelationOfParent
.getSynonym();
1261 inferredEpithet
= createInferredEpithets(taxon
,
1262 zooHashMap
, taxonName
, epithetOfTaxon
,
1263 infragenericEpithetOfTaxon
,
1264 infraspecificEpithetOfTaxon
,
1265 taxonNames
, parentName
,
1269 inferredSynonyms
.add(inferredEpithet
);
1270 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1271 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1274 if (doWithMisappliedNames
){
1276 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1277 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1279 inferredEpithet
= createInferredEpithets(taxon
,
1280 zooHashMap
, taxonName
, epithetOfTaxon
,
1281 infragenericEpithetOfTaxon
,
1282 infraspecificEpithetOfTaxon
,
1283 taxonNames
, parentName
,
1286 inferredSynonyms
.add(inferredEpithet
);
1287 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1288 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1292 if (!taxonNames
.isEmpty()){
1293 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1294 ZoologicalName name
;
1295 if (!synNotInCDM
.isEmpty()){
1296 inferredSynonymsToBeRemoved
.clear();
1298 for (Synonym syn
:inferredSynonyms
){
1299 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1300 if (!synNotInCDM
.contains(name
.getNameCache())){
1301 inferredSynonymsToBeRemoved
.add(syn
);
1305 // Remove identified Synonyms from inferredSynonyms
1306 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1307 inferredSynonyms
.remove(synonym
);
1312 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1315 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1316 TaxonNameBase synName
;
1317 ZoologicalName inferredSynName
;
1319 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1320 inferredGenus
= createInferredGenus(taxon
,
1321 zooHashMap
, taxonName
, epithetOfTaxon
,
1322 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1324 inferredSynonyms
.add(inferredGenus
);
1325 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1326 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1331 if (doWithMisappliedNames
){
1333 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1334 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1335 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1337 inferredSynonyms
.add(inferredGenus
);
1338 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1339 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1344 if (!taxonNames
.isEmpty()){
1345 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1346 ZoologicalName name
;
1347 if (!synNotInCDM
.isEmpty()){
1348 inferredSynonymsToBeRemoved
.clear();
1350 for (Synonym syn
:inferredSynonyms
){
1351 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1352 if (!synNotInCDM
.contains(name
.getNameCache())){
1353 inferredSynonymsToBeRemoved
.add(syn
);
1357 // Remove identified Synonyms from inferredSynonyms
1358 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1359 inferredSynonyms
.remove(synonym
);
1364 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1366 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1367 ZoologicalName inferredSynName
;
1368 //for all synonyms of the parent...
1369 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1370 TaxonNameBase synName
;
1371 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1372 synName
= synParent
.getName();
1374 HibernateProxyHelper
.deproxy(synParent
);
1376 // Set the sourceReference
1377 sourceReference
= synParent
.getSec();
1379 // Determine the idInSource
1380 String idInSourceParent
= getIdInSource(synParent
);
1382 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1383 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1384 String synParentInfragenericName
= null;
1385 String synParentSpecificEpithet
= null;
1387 if (parentSynZooName
.isInfraGeneric()){
1388 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1390 if (parentSynZooName
.isSpecies()){
1391 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1394 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1395 synonymsGenus.put(synGenusName, idInSource);
1398 //for all synonyms of the taxon
1400 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1402 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1403 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1404 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1406 synParentInfragenericName
,
1407 synParentSpecificEpithet
, syn
, zooHashMap
);
1409 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1410 inferredSynonyms
.add(potentialCombination
);
1411 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1412 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1419 if (doWithMisappliedNames
){
1421 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1423 TaxonNameBase misappliedParentName
;
1425 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1426 misappliedParentName
= misappliedParent
.getName();
1428 HibernateProxyHelper
.deproxy(misappliedParent
);
1430 // Set the sourceReference
1431 sourceReference
= misappliedParent
.getSec();
1433 // Determine the idInSource
1434 String idInSourceParent
= getIdInSource(misappliedParent
);
1436 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1437 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1438 String synParentInfragenericName
= null;
1439 String synParentSpecificEpithet
= null;
1441 if (parentSynZooName
.isInfraGeneric()){
1442 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1444 if (parentSynZooName
.isSpecies()){
1445 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1449 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1450 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1451 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1452 potentialCombination
= createPotentialCombination(
1453 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1455 synParentInfragenericName
,
1456 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1459 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1460 inferredSynonyms
.add(potentialCombination
);
1461 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1462 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1467 if (!taxonNames
.isEmpty()){
1468 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1469 ZoologicalName name
;
1470 if (!synNotInCDM
.isEmpty()){
1471 inferredSynonymsToBeRemoved
.clear();
1472 for (Synonym syn
:inferredSynonyms
){
1474 name
= (ZoologicalName
) syn
.getName();
1475 }catch (ClassCastException e
){
1476 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1478 if (!synNotInCDM
.contains(name
.getNameCache())){
1479 inferredSynonymsToBeRemoved
.add(syn
);
1482 // Remove identified Synonyms from inferredSynonyms
1483 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1484 inferredSynonyms
.remove(synonym
);
1490 logger
.info("The synonymrelationship type is not defined.");
1491 return inferredSynonyms
;
1498 return inferredSynonyms
;
1501 private Synonym
createPotentialCombination(String idInSourceParent
,
1502 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1503 String synParentInfragenericName
, String synParentSpecificEpithet
,
1504 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1505 Synonym potentialCombination
;
1506 Reference sourceReference
;
1507 ZoologicalName inferredSynName
;
1508 HibernateProxyHelper
.deproxy(syn
);
1510 // Set sourceReference
1511 sourceReference
= syn
.getSec();
1512 if (sourceReference
== null){
1513 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1515 if (!parentSynZooName
.getTaxa().isEmpty()){
1516 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
1518 sourceReference
= taxon
.getSec();
1521 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1523 String synTaxonInfraSpecificName
= null;
1525 if (parentSynZooName
.isSpecies()){
1526 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1529 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1530 synonymsEpithet.add(epithetName);
1533 //create potential combinations...
1534 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1536 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1537 if (zooSynName
.isSpecies()){
1538 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1539 if (parentSynZooName
.isInfraGeneric()){
1540 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1543 if (zooSynName
.isInfraSpecific()){
1544 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1545 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1547 if (parentSynZooName
.isInfraGeneric()){
1548 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1552 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1554 // Set the sourceReference
1555 potentialCombination
.setSec(sourceReference
);
1558 // Determine the idInSource
1559 String idInSourceSyn
= getIdInSource(syn
);
1561 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1562 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1563 inferredSynName
.addSource(originalSource
);
1564 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1565 potentialCombination
.addSource(originalSource
);
1568 inferredSynName
.generateTitle();
1570 return potentialCombination
;
1573 private Synonym
createInferredGenus(Taxon taxon
,
1574 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1575 String epithetOfTaxon
, String genusOfTaxon
,
1576 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1579 Synonym inferredGenus
;
1580 TaxonNameBase synName
;
1581 ZoologicalName inferredSynName
;
1582 synName
=syn
.getName();
1583 HibernateProxyHelper
.deproxy(syn
);
1585 // Determine the idInSource
1586 String idInSourceSyn
= getIdInSource(syn
);
1587 String idInSourceTaxon
= getIdInSource(taxon
);
1588 // Determine the sourceReference
1589 Reference sourceReference
= syn
.getSec();
1591 //logger.warn(sourceReference.getTitleCache());
1593 synName
= syn
.getName();
1594 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1595 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1596 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1597 synonymsEpithet.add(synSpeciesEpithetName);
1600 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1601 //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...
1604 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1605 if (zooParentName
.isInfraGeneric()){
1606 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1609 if (taxonName
.isSpecies()){
1610 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1612 if (taxonName
.isInfraSpecific()){
1613 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1614 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1618 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1620 // Set the sourceReference
1621 inferredGenus
.setSec(sourceReference
);
1623 // Add the original source
1624 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1625 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1626 inferredGenus
.addSource(originalSource
);
1628 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1629 inferredSynName
.addSource(originalSource
);
1630 originalSource
= null;
1633 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
1634 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1635 inferredGenus
.addSource(originalSource
);
1637 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1638 inferredSynName
.addSource(originalSource
);
1639 originalSource
= null;
1642 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1644 inferredSynName
.generateTitle();
1647 return inferredGenus
;
1650 private Synonym
createInferredEpithets(Taxon taxon
,
1651 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1652 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1653 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1654 TaxonNameBase parentName
, TaxonBase syn
) {
1656 Synonym inferredEpithet
;
1657 TaxonNameBase synName
;
1658 ZoologicalName inferredSynName
;
1659 HibernateProxyHelper
.deproxy(syn
);
1661 // Determine the idInSource
1662 String idInSourceSyn
= getIdInSource(syn
);
1663 String idInSourceTaxon
= getIdInSource(taxon
);
1664 // Determine the sourceReference
1665 Reference sourceReference
= syn
.getSec();
1667 if (sourceReference
== null){
1668 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1670 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
1671 sourceReference
= taxon
.getSec();
1674 synName
= syn
.getName();
1675 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1676 String synGenusName
= zooSynName
.getGenusOrUninomial();
1677 String synInfraGenericEpithet
= null;
1678 String synSpecificEpithet
= null;
1680 if (zooSynName
.getInfraGenericEpithet() != null){
1681 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1684 if (zooSynName
.isInfraSpecific()){
1685 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1688 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1689 synonymsGenus.put(synGenusName, idInSource);
1692 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1694 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1695 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1696 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1698 inferredSynName
.setGenusOrUninomial(synGenusName
);
1700 if (parentName
.isInfraGeneric()){
1701 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1703 if (taxonName
.isSpecies()){
1704 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1705 }else if (taxonName
.isInfraSpecific()){
1706 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1707 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1710 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1712 // Set the sourceReference
1713 inferredEpithet
.setSec(sourceReference
);
1715 /* Add the original source
1716 if (idInSource != null) {
1717 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1720 Reference citation = getCitation(syn);
1721 if (citation != null) {
1722 originalSource.setCitation(citation);
1723 inferredEpithet.addSource(originalSource);
1726 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1728 IdentifiableSource originalSource
;
1729 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1731 inferredEpithet
.addSource(originalSource
);
1733 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1735 inferredSynName
.addSource(originalSource
);
1739 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1741 inferredSynName
.generateTitle();
1742 return inferredEpithet
;
1746 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1747 * Very likely only useful for createInferredSynonyms().
1752 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1753 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1754 if (taxonName
== null) {
1755 taxonName
= zooHashMap
.get(uuid
);
1761 * Returns the idInSource for a given Synonym.
1764 private String
getIdInSource(TaxonBase taxonBase
) {
1765 String idInSource
= null;
1766 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1767 if (sources
.size() == 1) {
1768 IdentifiableSource source
= sources
.iterator().next();
1769 if (source
!= null) {
1770 idInSource
= source
.getIdInSource();
1772 } else if (sources
.size() > 1) {
1775 for (IdentifiableSource source
: sources
) {
1776 idInSource
+= source
.getIdInSource();
1777 if (count
< sources
.size()) {
1782 } else if (sources
.size() == 0){
1783 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
1792 * Returns the citation for a given Synonym.
1795 private Reference
getCitation(Synonym syn
) {
1796 Reference citation
= null;
1797 Set
<IdentifiableSource
> sources
= syn
.getSources();
1798 if (sources
.size() == 1) {
1799 IdentifiableSource source
= sources
.iterator().next();
1800 if (source
!= null) {
1801 citation
= source
.getCitation();
1803 } else if (sources
.size() > 1) {
1804 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1810 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1811 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1813 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1814 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1815 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1817 return inferredSynonyms
;