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
.Feature
;
61 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
62 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
63 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
64 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
65 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
66 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
67 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
68 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
69 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
70 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
71 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
72 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
73 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
74 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
75 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
76 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
77 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
78 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
79 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
80 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
81 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
82 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
83 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
84 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
85 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
86 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
87 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
88 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
89 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
90 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
91 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
92 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
96 * @author a.kohlbecker
101 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
102 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
103 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
105 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
107 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
109 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
113 private ITaxonNameDao nameDao
;
116 private INameService nameService
;
119 private ICdmGenericDao genericDao
;
122 private IDescriptionService descriptionService
;
125 private IOrderedTermVocabularyDao orderedVocabularyDao
;
130 public TaxonServiceImpl(){
131 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
135 * FIXME Candidate for harmonization
136 * rename searchByName ?
138 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
139 return dao
.getTaxaByName(name
, sec
);
143 * FIXME Candidate for harmonization
144 * list(Synonym.class, ...)
146 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
148 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
149 return dao
.getAllSynonyms(limit
, start
);
153 * FIXME Candidate for harmonization
154 * list(Taxon.class, ...)
156 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
158 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
159 return dao
.getAllTaxa(limit
, start
);
163 * FIXME Candidate for harmonization
164 * merge with getRootTaxa(Reference sec, ..., ...)
166 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
168 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
169 if (cdmFetch
== null){
170 cdmFetch
= CdmFetch
.NO_FETCH();
172 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
177 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
179 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
180 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
184 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
186 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
187 return dao
.getAllRelationships(limit
, start
);
191 * FIXME Candidate for harmonization
192 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
195 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
197 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
198 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
199 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
200 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
201 return taxonRelTypeVocabulary
;
208 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
210 @Transactional(readOnly
= false)
211 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
213 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
214 synonymName
.removeTaxonBase(synonym
);
215 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
216 taxonName
.removeTaxonBase(acceptedTaxon
);
218 synonym
.setName(taxonName
);
219 acceptedTaxon
.setName(synonymName
);
221 // the accepted taxon needs a new uuid because the concept has changed
222 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
223 //acceptedTaxon.setUuid(UUID.randomUUID());
228 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
230 //TODO correct delete handling still needs to be implemented / checked
232 @Transactional(readOnly
= false)
233 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
235 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
236 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
237 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
239 //check synonym is not homotypic
240 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
241 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
242 throw new HomotypicalGroupChangeException(message
);
245 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
247 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
248 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
250 for (Synonym heteroSynonym
: heteroSynonyms
){
251 if (synonym
.equals(heteroSynonym
)){
252 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
254 //move synonyms in same homotypic group to new accepted taxon
255 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
259 //synonym.getName().removeTaxonBase(synonym);
260 //TODO correct delete handling still needs to be implemented / checked
262 // deleteSynonym(synonym, taxon, false);
265 this.delete(synonym
);
267 } catch (Exception e
) {
268 logger
.info("Can't delete old synonym from database");
272 return newAcceptedTaxon
;
276 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
278 // Get name from synonym
279 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
281 // remove synonym from taxon
282 toTaxon
.removeSynonym(synonym
);
284 // Create a taxon with synonym name
285 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
287 // Add taxon relation
288 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
290 // since we are swapping names, we have to detach the name from the synonym completely.
291 // Otherwise the synonym will still be in the list of typified names.
292 synonym
.getName().removeTaxonBase(synonym
);
299 * @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)
301 @Transactional(readOnly
= false)
303 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
304 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
306 TaxonNameBase synonymName
= synonym
.getName();
307 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
311 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
312 newHomotypicalGroup
.addTypifiedName(synonymName
);
314 //remove existing basionym relationships
315 synonymName
.removeBasionyms();
317 //add basionym relationship
318 if (setBasionymRelationIfApplicable
){
319 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
320 for (TaxonNameBase basionym
: basionyms
){
321 synonymName
.addBasionym(basionym
);
325 //set synonym relationship correctly
326 // SynonymRelationship relToTaxon = null;
327 boolean relToTargetTaxonExists
= false;
328 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
329 for (SynonymRelationship rel
: existingRelations
){
330 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
331 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
332 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
333 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
334 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
335 rel
.setType(newRelationType
);
336 //TODO handle citation and microCitation
339 relToTargetTaxonExists
= true;
341 if (removeFromOtherTaxa
){
342 acceptedTaxon
.removeSynonym(synonym
, false);
348 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
349 Taxon acceptedTaxon
= targetTaxon
;
350 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
351 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
352 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
353 //TODO handle citation and microCitation
354 Reference citation
= null;
355 String microCitation
= null;
356 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
363 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
366 @Transactional(readOnly
= false)
367 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
369 clazz
= TaxonBase
.class;
371 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
375 protected void setDao(ITaxonDao dao
) {
380 * @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)
382 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
383 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
385 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
386 if(numberOfResults
> 0) { // no point checking again
387 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
390 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
394 * @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)
396 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
397 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
399 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
400 if(numberOfResults
> 0) { // no point checking again
401 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
408 * @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)
410 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
411 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
413 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
414 if(numberOfResults
> 0) { // no point checking again
415 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
421 * @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)
423 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
424 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
426 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
427 if(numberOfResults
> 0) { // no point checking again
428 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
430 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
434 * @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)
436 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
437 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
439 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
440 if(numberOfResults
> 0) { // no point checking again
441 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
447 * @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)
449 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
450 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
452 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
453 if(numberOfResults
> 0) { // no point checking again
454 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
456 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
460 * @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)
462 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
463 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
465 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
466 if(numberOfResults
> 0) { // no point checking again
467 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
470 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
474 * @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)
476 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
477 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
479 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
480 if(numberOfResults
> 0) { // no point checking again
481 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
484 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
488 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
490 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
491 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
492 return t
.getHomotypicSynonymsByHomotypicGroup();
496 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
498 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
499 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
500 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
501 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
502 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
503 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
505 return heterotypicSynonymyGroups
;
508 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator
){
510 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
511 // Class<? extends TaxonBase> clazz = null;
512 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
513 // clazz = TaxonBase.class;
514 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
515 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
516 // } else if(configurator.isDoTaxa()) {
517 // clazz = Taxon.class;
518 // //propertyPath = configurator.getTaxonPropertyPath();
519 // } else if (configurator.isDoSynonyms()) {
520 // clazz = Synonym.class;
521 // //propertyPath = configurator.getSynonymPropertyPath();
525 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
530 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
532 public Pager
<IdentifiableEntity
> findTaxaAndNames(ITaxonServiceConfigurator configurator
) {
534 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
535 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
536 List
<TaxonBase
> taxa
= null;
539 long numberTaxaResults
= 0L;
542 List
<String
> propertyPath
= new ArrayList
<String
>();
543 if(configurator
.getTaxonPropertyPath() != null){
544 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
548 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
549 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
551 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
552 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
553 configurator
.getNamedAreas());
556 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
557 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
558 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
559 configurator
.getMatchMode(), configurator
.getNamedAreas(),
560 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
564 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
567 results
.addAll(taxa
);
570 numberOfResults
+= numberTaxaResults
;
572 // Names without taxa
573 if (configurator
.isDoNamesWithoutTaxa()) {
574 int numberNameResults
= 0;
576 List
<?
extends TaxonNameBase
<?
,?
>> names
=
577 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
578 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
579 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
580 if (names
.size() > 0) {
581 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
582 if (taxonName
.getTaxonBases().size() == 0) {
583 results
.add(taxonName
);
587 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
588 numberOfResults
+= numberNameResults
;
592 // Taxa from common names
594 if (configurator
.isDoTaxaByCommonNames()) {
595 taxa
= new ArrayList
<TaxonBase
>();
596 numberTaxaResults
= 0;
597 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
598 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
600 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
601 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
602 for( Object
[] entry
: commonNameResults
) {
603 taxa
.add((TaxonBase
) entry
[0]);
607 results
.addAll(taxa
);
609 numberOfResults
+= numberTaxaResults
;
613 return new DefaultPagerImpl
<IdentifiableEntity
>
614 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
617 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
618 return dao
.getUuidAndTitleCache();
622 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
624 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
625 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
626 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
627 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
628 for (TaxonDescription taxDesc
: descriptions
){
629 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
630 for (DescriptionElementBase descElem
: elements
){
631 for(Media media
: descElem
.getMedia()){
633 //find the best matching representation
634 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
643 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
645 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
646 return this.dao
.findById(listOfIDs
);
650 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
652 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
653 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
657 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
659 public int countAllRelationships() {
660 return this.dao
.countAllRelationships();
667 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
669 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
670 return this.dao
.findIdenticalTaxonNames(propertyPath
);
675 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
678 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
680 config
= new TaxonDeletionConfigurator();
684 if (! config
.isDeleteTaxonNodes()){
685 if (taxon
.getTaxonNodes().size() > 0){
686 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
687 throw new ReferencedObjectUndeletableException(message
);
692 // SynonymRelationShip
693 if (config
.isDeleteSynonymRelations()){
694 boolean removeSynonymNameFromHomotypicalGroup
= false;
695 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
696 Synonym synonym
= synRel
.getSynonym();
697 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
698 if (config
.isDeleteSynonymsIfPossible()){
700 boolean newHomotypicGroupIfNeeded
= true;
701 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
703 deleteSynonymRelationships(synonym
, taxon
);
709 if (! config
.isDeleteTaxonRelationships()){
710 if (taxon
.getTaxonRelations().size() > 0){
711 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.";
712 throw new ReferencedObjectUndeletableException(message
);
718 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
720 for (TaxonDescription desc
: descriptions
){
721 if (config
.isDeleteDescriptions()){
722 //TODO use description delete configurator ?
723 //FIXME check if description is ALWAYS deletable
724 descriptionService
.delete(desc
);
726 if (desc
.getDescribedSpecimenOrObservations().size()>0){
727 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
728 " which also describes specimens or abservations";
729 throw new ReferencedObjectUndeletableException(message
);
735 //check references with only reverse mapping
736 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
737 for (CdmBase referencingObject
: referencingObjects
){
738 //IIdentificationKeys (Media, Polytomous, MultiAccess)
739 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
740 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
741 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
742 throw new ReferencedObjectUndeletableException(message
);
747 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
748 String message
= "Taxon can't be deleted as it is used in polytomous key node";
749 throw new ReferencedObjectUndeletableException(message
);
753 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
754 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
755 throw new ReferencedObjectUndeletableException(message
);
761 if (config
.isDeleteNameIfPossible()){
763 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
764 } catch (ReferencedObjectUndeletableException e
) {
766 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
773 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
775 @Transactional(readOnly
= false)
777 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
778 if (synonym
== null){
781 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
783 //remove synonymRelationship
784 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
788 taxonSet
.addAll(synonym
.getAcceptedTaxa());
790 for (Taxon relatedTaxon
: taxonSet
){
791 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
792 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
794 this.saveOrUpdate(synonym
);
796 //TODO remove name from homotypical group?
798 //remove synonym (if necessary)
799 if (synonym
.getSynonymRelations().isEmpty()){
800 TaxonNameBase
<?
,?
> name
= synonym
.getName();
801 synonym
.setName(null);
804 //remove name if possible (and required)
805 if (name
!= null && removeNameIfPossible
){
807 nameService
.delete(name
, new NameDeletionConfigurator());
808 }catch (DataChangeNoRollbackException ex
){
809 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
817 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
819 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
821 return this.dao
.findIdenticalNamesNew(propertyPath
);
825 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
827 public String
getPhylumName(TaxonNameBase name
){
828 return this.dao
.getPhylumName(name
);
832 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
834 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
835 return dao
.deleteSynonymRelationships(syn
, taxon
);
839 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
841 public long deleteSynonymRelationships(Synonym syn
) {
842 return dao
.deleteSynonymRelationships(syn
, null);
847 * @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)
849 public List
<SynonymRelationship
> listSynonymRelationships(
850 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
851 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
852 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
854 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
855 if(numberOfResults
> 0) { // no point checking again
856 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
862 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
865 public Taxon
findBestMatchingTaxon(String taxonName
) {
866 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
867 config
.setTaxonNameTitle(taxonName
);
868 return findBestMatchingTaxon(config
);
874 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
876 Taxon bestCandidate
= null;
878 // 1. search for acceptet taxa
879 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
880 boolean bestCandidateMatchesSecUuid
= false;
881 boolean bestCandidateIsInClassification
= false;
882 int countEqualCandidates
= 0;
883 for(TaxonBase taxonBaseCandidate
: taxonList
){
884 if(taxonBaseCandidate
instanceof Taxon
){
885 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
886 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
887 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
889 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
890 bestCandidate
= newCanditate
;
891 countEqualCandidates
= 1;
892 bestCandidateMatchesSecUuid
= true;
896 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
897 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
899 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
900 bestCandidate
= newCanditate
;
901 countEqualCandidates
= 1;
902 bestCandidateIsInClassification
= true;
905 if (bestCandidate
== null){
906 bestCandidate
= newCanditate
;
907 countEqualCandidates
= 1;
911 }else{ //not Taxon.class
914 countEqualCandidates
++;
917 if (bestCandidate
!= null){
918 if(countEqualCandidates
> 1){
919 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
920 return bestCandidate
;
922 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
923 return bestCandidate
;
928 // 2. search for synonyms
929 if (config
.isIncludeSynonyms()){
930 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
931 for(TaxonBase taxonBase
: synonymList
){
932 if(taxonBase
instanceof Synonym
){
933 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
934 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
935 if(!acceptetdCandidates
.isEmpty()){
936 bestCandidate
= acceptetdCandidates
.iterator().next();
937 if(acceptetdCandidates
.size() == 1){
938 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
939 return bestCandidate
;
941 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
942 return bestCandidate
;
944 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
950 } catch (Exception e
){
954 return bestCandidate
;
957 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
958 UUID configClassificationUuid
= config
.getClassificationUuid();
959 if (configClassificationUuid
== null){
962 for (TaxonNode node
: taxon
.getTaxonNodes()){
963 UUID classUuid
= node
.getClassification().getUuid();
964 if (configClassificationUuid
.equals(classUuid
)){
971 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
972 UUID configSecUuid
= config
.getSecUuid();
973 if (configSecUuid
== null){
976 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
977 return configSecUuid
.equals(taxonSecUuid
);
981 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
984 public Synonym
findBestMatchingSynonym(String taxonName
) {
985 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
986 if(! synonymList
.isEmpty()){
987 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
988 if(synonymList
.size() == 1){
989 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
992 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1001 * @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)
1004 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1005 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1007 Synonym synonym
= oldSynonymRelation
.getSynonym();
1008 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1009 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1010 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1011 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1012 //set default relationship type
1013 if (newSynonymRelationshipType
== null){
1014 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1016 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1018 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1019 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1020 boolean isSingleInGroup
= !(hgSize
> 1);
1022 if (! isSingleInGroup
){
1023 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1024 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1025 if (isHomotypicToAccepted
){
1026 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.";
1027 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1028 message
= String
.format(message
, homotypicRelatives
);
1029 throw new HomotypicalGroupChangeException(message
);
1031 if (! moveHomotypicGroup
){
1032 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.";
1033 throw new HomotypicalGroupChangeException(message
);
1036 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1038 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1040 SynonymRelationship result
= null;
1041 //move all synonyms to new taxon
1042 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1043 for (Synonym syn
: homotypicSynonyms
){
1044 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1045 for (SynonymRelationship synRelation
: synRelations
){
1046 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1047 Reference
<?
> newReference
= reference
;
1048 if (newReference
== null && keepReference
){
1049 newReference
= synRelation
.getCitation();
1051 String newRefDetail
= referenceDetail
;
1052 if (newRefDetail
== null && keepReference
){
1053 newRefDetail
= synRelation
.getCitationMicroReference();
1055 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1056 fromTaxon
.removeSynonymRelation(synRelation
, false);
1058 //change homotypic group of synonym if relType is 'homotypic'
1059 // if (newRelTypeIsHomotypic){
1060 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1063 if (synRelation
.equals(oldSynonymRelation
)){
1064 result
= newSynRelation
;
1070 saveOrUpdate(newTaxon
);
1071 //Assert that there is a result
1072 if (result
== null){
1073 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1074 throw new IllegalStateException(message
);
1080 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1083 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1084 return dao
.getUuidAndTitleCacheTaxon();
1088 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1091 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1092 return dao
.getUuidAndTitleCacheSynonym();
1096 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1097 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1098 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1099 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1101 Class
<?
extends DescriptionElementBase
> directorySelectClass
= DescriptionElementBase
.class;
1103 directorySelectClass
= clazz
;
1106 Set
<String
> freetextFields
= new HashSet
<String
>();
1107 // ---- search criteria
1108 freetextFields
.add("titleCache");
1109 StringBuilder luceneQueryTemplate
= new StringBuilder();
1110 luceneQueryTemplate
.append("+(");
1111 luceneQueryTemplate
.append("titleCache:%1$s ");
1113 freetextFields
.add("name");
1114 if(languages
== null || languages
.size() == 0){
1115 luceneQueryTemplate
.append("name:%1$s ");
1117 luceneQueryTemplate
.append("(+name:%1$s ");
1118 for(Language lang
: languages
){
1119 luceneQueryTemplate
.append(" +language.uuid:" + lang
.getUuid().toString());
1121 luceneQueryTemplate
.append(")");
1123 // text field from TextData
1124 freetextFields
.add("text.ALL");
1125 appendLocalizedFieldQuery("text", languages
, luceneQueryTemplate
).append(" ");
1126 // state field from CategoricalData
1127 freetextFields
.add("states.state.representation.ALL");
1128 appendLocalizedFieldQuery("states.state.representation", languages
, luceneQueryTemplate
).append(" ");
1129 // state field from CategoricalData
1130 freetextFields
.add("states.modifyingText.ALL");
1131 appendLocalizedFieldQuery("states.modifyingText", languages
, luceneQueryTemplate
).append(" ");
1132 luceneQueryTemplate
.append(") ");
1134 if(classification
!= null){
1135 luceneQueryTemplate
.append("+inDescription.taxon.taxonNodes.classification.id:").append(classification
.getId()).append(" ");
1138 if(features
!= null && features
.size() > 0 ){
1139 luceneQueryTemplate
.append("+feature.uuid:(");
1140 for(Feature feature
: features
){
1141 luceneQueryTemplate
.append(feature
.getUuid()).append(" ");
1143 luceneQueryTemplate
.append(") ");
1146 // the description must be associated with a taxon
1147 // TODO open range queries [0 TO *] not working in the current version of lucene (https://issues.apache.org/jira/browse/LUCENE-995)
1148 // so we are using integer maximum as workaround
1149 luceneQueryTemplate
.append("+inDescription.taxon.id:[0 TO " + Integer
.MAX_VALUE
+ "] ");
1151 String luceneQueryStr
= String
.format(luceneQueryTemplate
.toString(), queryString
);
1154 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", false)};
1156 // ---- execute criteria
1157 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), directorySelectClass
);
1159 Query luceneQuery
= luceneSearch
.parse(luceneQueryStr
);
1160 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(luceneQuery
, clazz
, pageSize
, pageNumber
, sortFields
);
1162 String
[] highlightFields
= null;
1163 if(highlightFragments
){
1164 highlightFields
= freetextFields
.toArray(new String
[freetextFields
.size()]);
1167 // initialize taxa, thighlight matches ....
1168 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneQuery
);
1169 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1170 topDocsResultSet
, highlightFields
, dao
, "inDescription.taxon.id", propertyPaths
);
1172 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
1177 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1178 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1179 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1181 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1182 * or {@link MultilanguageTextFieldBridge }
1183 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1184 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1185 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1187 * TODO move to utiliy class !!!!!!!!
1189 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1191 if(stringBuilder
== null){
1192 stringBuilder
= new StringBuilder();
1194 if(languages
== null || languages
.size() == 0){
1195 stringBuilder
.append(name
+ ".ALL:%1$s ");
1197 for(Language lang
: languages
){
1198 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":%1$s ");
1201 return stringBuilder
;
1204 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1205 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1206 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1208 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1211 UUID uuid
= taxon
.getName().getUuid();
1212 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1213 String epithetOfTaxon
= null;
1214 String infragenericEpithetOfTaxon
= null;
1215 String infraspecificEpithetOfTaxon
= null;
1216 if (taxonName
.isSpecies()){
1217 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1218 } else if (taxonName
.isInfraGeneric()){
1219 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1220 } else if (taxonName
.isInfraSpecific()){
1221 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1223 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1224 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1225 List
<String
> taxonNames
= new ArrayList
<String
>();
1227 for (TaxonNode node
: nodes
){
1228 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1229 // List<String> synonymsEpithet = new ArrayList<String>();
1231 if (node
.getClassification().equals(classification
)){
1232 if (!node
.isTopmostNode()){
1233 TaxonNode parent
= (TaxonNode
)node
.getParent();
1234 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1235 TaxonNameBase parentName
= parent
.getTaxon().getName();
1236 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1237 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1238 Rank rankOfTaxon
= taxonName
.getRank();
1241 //create inferred synonyms for species, subspecies
1242 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1244 Synonym inferredEpithet
= null;
1245 Synonym inferredGenus
= null;
1246 Synonym potentialCombination
= null;
1248 List
<String
> propertyPaths
= new ArrayList
<String
>();
1249 propertyPaths
.add("synonym");
1250 propertyPaths
.add("synonym.name");
1251 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1252 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1254 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1255 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1257 List
<TaxonRelationship
> taxonRelListParent
= null;
1258 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1259 if (doWithMisappliedNames
){
1260 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1261 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1265 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1266 Set
<String
> genusNames
= new HashSet
<String
>();
1268 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1269 Synonym syn
= synonymRelationOfParent
.getSynonym();
1271 inferredEpithet
= createInferredEpithets(taxon
,
1272 zooHashMap
, taxonName
, epithetOfTaxon
,
1273 infragenericEpithetOfTaxon
,
1274 infraspecificEpithetOfTaxon
,
1275 taxonNames
, parentName
,
1279 inferredSynonyms
.add(inferredEpithet
);
1280 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1281 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1284 if (doWithMisappliedNames
){
1286 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1287 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1289 inferredEpithet
= createInferredEpithets(taxon
,
1290 zooHashMap
, taxonName
, epithetOfTaxon
,
1291 infragenericEpithetOfTaxon
,
1292 infraspecificEpithetOfTaxon
,
1293 taxonNames
, parentName
,
1296 inferredSynonyms
.add(inferredEpithet
);
1297 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1298 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1302 if (!taxonNames
.isEmpty()){
1303 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1304 ZoologicalName name
;
1305 if (!synNotInCDM
.isEmpty()){
1306 inferredSynonymsToBeRemoved
.clear();
1308 for (Synonym syn
:inferredSynonyms
){
1309 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1310 if (!synNotInCDM
.contains(name
.getNameCache())){
1311 inferredSynonymsToBeRemoved
.add(syn
);
1315 // Remove identified Synonyms from inferredSynonyms
1316 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1317 inferredSynonyms
.remove(synonym
);
1322 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1325 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1326 TaxonNameBase synName
;
1327 ZoologicalName inferredSynName
;
1329 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1330 inferredGenus
= createInferredGenus(taxon
,
1331 zooHashMap
, taxonName
, epithetOfTaxon
,
1332 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1334 inferredSynonyms
.add(inferredGenus
);
1335 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1336 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1341 if (doWithMisappliedNames
){
1343 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1344 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1345 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1347 inferredSynonyms
.add(inferredGenus
);
1348 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1349 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1354 if (!taxonNames
.isEmpty()){
1355 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1356 ZoologicalName name
;
1357 if (!synNotInCDM
.isEmpty()){
1358 inferredSynonymsToBeRemoved
.clear();
1360 for (Synonym syn
:inferredSynonyms
){
1361 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1362 if (!synNotInCDM
.contains(name
.getNameCache())){
1363 inferredSynonymsToBeRemoved
.add(syn
);
1367 // Remove identified Synonyms from inferredSynonyms
1368 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1369 inferredSynonyms
.remove(synonym
);
1374 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1376 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1377 ZoologicalName inferredSynName
;
1378 //for all synonyms of the parent...
1379 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1380 TaxonNameBase synName
;
1381 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1382 synName
= synParent
.getName();
1384 HibernateProxyHelper
.deproxy(synParent
);
1386 // Set the sourceReference
1387 sourceReference
= synParent
.getSec();
1389 // Determine the idInSource
1390 String idInSourceParent
= getIdInSource(synParent
);
1392 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1393 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1394 String synParentInfragenericName
= null;
1395 String synParentSpecificEpithet
= null;
1397 if (parentSynZooName
.isInfraGeneric()){
1398 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1400 if (parentSynZooName
.isSpecies()){
1401 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1404 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1405 synonymsGenus.put(synGenusName, idInSource);
1408 //for all synonyms of the taxon
1410 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1412 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1413 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1414 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1416 synParentInfragenericName
,
1417 synParentSpecificEpithet
, syn
, zooHashMap
);
1419 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1420 inferredSynonyms
.add(potentialCombination
);
1421 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1422 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1429 if (doWithMisappliedNames
){
1431 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1433 TaxonNameBase misappliedParentName
;
1435 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1436 misappliedParentName
= misappliedParent
.getName();
1438 HibernateProxyHelper
.deproxy(misappliedParent
);
1440 // Set the sourceReference
1441 sourceReference
= misappliedParent
.getSec();
1443 // Determine the idInSource
1444 String idInSourceParent
= getIdInSource(misappliedParent
);
1446 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1447 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1448 String synParentInfragenericName
= null;
1449 String synParentSpecificEpithet
= null;
1451 if (parentSynZooName
.isInfraGeneric()){
1452 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1454 if (parentSynZooName
.isSpecies()){
1455 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1459 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1460 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1461 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1462 potentialCombination
= createPotentialCombination(
1463 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1465 synParentInfragenericName
,
1466 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1469 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1470 inferredSynonyms
.add(potentialCombination
);
1471 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1472 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1477 if (!taxonNames
.isEmpty()){
1478 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1479 ZoologicalName name
;
1480 if (!synNotInCDM
.isEmpty()){
1481 inferredSynonymsToBeRemoved
.clear();
1482 for (Synonym syn
:inferredSynonyms
){
1484 name
= (ZoologicalName
) syn
.getName();
1485 }catch (ClassCastException e
){
1486 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1488 if (!synNotInCDM
.contains(name
.getNameCache())){
1489 inferredSynonymsToBeRemoved
.add(syn
);
1492 // Remove identified Synonyms from inferredSynonyms
1493 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1494 inferredSynonyms
.remove(synonym
);
1500 logger
.info("The synonymrelationship type is not defined.");
1501 return inferredSynonyms
;
1508 return inferredSynonyms
;
1511 private Synonym
createPotentialCombination(String idInSourceParent
,
1512 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1513 String synParentInfragenericName
, String synParentSpecificEpithet
,
1514 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1515 Synonym potentialCombination
;
1516 Reference sourceReference
;
1517 ZoologicalName inferredSynName
;
1518 HibernateProxyHelper
.deproxy(syn
);
1520 // Set sourceReference
1521 sourceReference
= syn
.getSec();
1522 if (sourceReference
== null){
1523 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1525 if (!parentSynZooName
.getTaxa().isEmpty()){
1526 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
1528 sourceReference
= taxon
.getSec();
1531 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1533 String synTaxonInfraSpecificName
= null;
1535 if (parentSynZooName
.isSpecies()){
1536 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1539 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1540 synonymsEpithet.add(epithetName);
1543 //create potential combinations...
1544 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1546 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1547 if (zooSynName
.isSpecies()){
1548 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1549 if (parentSynZooName
.isInfraGeneric()){
1550 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1553 if (zooSynName
.isInfraSpecific()){
1554 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1555 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1557 if (parentSynZooName
.isInfraGeneric()){
1558 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1562 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1564 // Set the sourceReference
1565 potentialCombination
.setSec(sourceReference
);
1568 // Determine the idInSource
1569 String idInSourceSyn
= getIdInSource(syn
);
1571 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1572 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1573 inferredSynName
.addSource(originalSource
);
1574 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1575 potentialCombination
.addSource(originalSource
);
1578 inferredSynName
.generateTitle();
1580 return potentialCombination
;
1583 private Synonym
createInferredGenus(Taxon taxon
,
1584 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1585 String epithetOfTaxon
, String genusOfTaxon
,
1586 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1589 Synonym inferredGenus
;
1590 TaxonNameBase synName
;
1591 ZoologicalName inferredSynName
;
1592 synName
=syn
.getName();
1593 HibernateProxyHelper
.deproxy(syn
);
1595 // Determine the idInSource
1596 String idInSourceSyn
= getIdInSource(syn
);
1597 String idInSourceTaxon
= getIdInSource(taxon
);
1598 // Determine the sourceReference
1599 Reference sourceReference
= syn
.getSec();
1601 //logger.warn(sourceReference.getTitleCache());
1603 synName
= syn
.getName();
1604 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1605 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1606 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1607 synonymsEpithet.add(synSpeciesEpithetName);
1610 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1611 //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...
1614 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1615 if (zooParentName
.isInfraGeneric()){
1616 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1619 if (taxonName
.isSpecies()){
1620 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1622 if (taxonName
.isInfraSpecific()){
1623 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1624 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1628 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1630 // Set the sourceReference
1631 inferredGenus
.setSec(sourceReference
);
1633 // Add the original source
1634 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1635 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1636 inferredGenus
.addSource(originalSource
);
1638 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1639 inferredSynName
.addSource(originalSource
);
1640 originalSource
= null;
1643 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
1644 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1645 inferredGenus
.addSource(originalSource
);
1647 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1648 inferredSynName
.addSource(originalSource
);
1649 originalSource
= null;
1652 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1654 inferredSynName
.generateTitle();
1657 return inferredGenus
;
1660 private Synonym
createInferredEpithets(Taxon taxon
,
1661 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1662 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1663 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1664 TaxonNameBase parentName
, TaxonBase syn
) {
1666 Synonym inferredEpithet
;
1667 TaxonNameBase synName
;
1668 ZoologicalName inferredSynName
;
1669 HibernateProxyHelper
.deproxy(syn
);
1671 // Determine the idInSource
1672 String idInSourceSyn
= getIdInSource(syn
);
1673 String idInSourceTaxon
= getIdInSource(taxon
);
1674 // Determine the sourceReference
1675 Reference sourceReference
= syn
.getSec();
1677 if (sourceReference
== null){
1678 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1680 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
1681 sourceReference
= taxon
.getSec();
1684 synName
= syn
.getName();
1685 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1686 String synGenusName
= zooSynName
.getGenusOrUninomial();
1687 String synInfraGenericEpithet
= null;
1688 String synSpecificEpithet
= null;
1690 if (zooSynName
.getInfraGenericEpithet() != null){
1691 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1694 if (zooSynName
.isInfraSpecific()){
1695 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1698 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1699 synonymsGenus.put(synGenusName, idInSource);
1702 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1704 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1705 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1706 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1708 inferredSynName
.setGenusOrUninomial(synGenusName
);
1710 if (parentName
.isInfraGeneric()){
1711 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1713 if (taxonName
.isSpecies()){
1714 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1715 }else if (taxonName
.isInfraSpecific()){
1716 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1717 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1720 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1722 // Set the sourceReference
1723 inferredEpithet
.setSec(sourceReference
);
1725 /* Add the original source
1726 if (idInSource != null) {
1727 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1730 Reference citation = getCitation(syn);
1731 if (citation != null) {
1732 originalSource.setCitation(citation);
1733 inferredEpithet.addSource(originalSource);
1736 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1738 IdentifiableSource originalSource
;
1739 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1741 inferredEpithet
.addSource(originalSource
);
1743 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1745 inferredSynName
.addSource(originalSource
);
1749 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1751 inferredSynName
.generateTitle();
1752 return inferredEpithet
;
1756 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1757 * Very likely only useful for createInferredSynonyms().
1762 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1763 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1764 if (taxonName
== null) {
1765 taxonName
= zooHashMap
.get(uuid
);
1771 * Returns the idInSource for a given Synonym.
1774 private String
getIdInSource(TaxonBase taxonBase
) {
1775 String idInSource
= null;
1776 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1777 if (sources
.size() == 1) {
1778 IdentifiableSource source
= sources
.iterator().next();
1779 if (source
!= null) {
1780 idInSource
= source
.getIdInSource();
1782 } else if (sources
.size() > 1) {
1785 for (IdentifiableSource source
: sources
) {
1786 idInSource
+= source
.getIdInSource();
1787 if (count
< sources
.size()) {
1792 } else if (sources
.size() == 0){
1793 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
1802 * Returns the citation for a given Synonym.
1805 private Reference
getCitation(Synonym syn
) {
1806 Reference citation
= null;
1807 Set
<IdentifiableSource
> sources
= syn
.getSources();
1808 if (sources
.size() == 1) {
1809 IdentifiableSource source
= sources
.iterator().next();
1810 if (source
!= null) {
1811 citation
= source
.getCitation();
1813 } else if (sources
.size() > 1) {
1814 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1820 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1821 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1823 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1824 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1825 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1827 return inferredSynonyms
;