3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.cdm
.api
.service
;
13 import java
.io
.IOException
;
14 import java
.util
.ArrayList
;
15 import java
.util
.HashMap
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
19 import java
.util
.UUID
;
21 import org
.apache
.log4j
.Logger
;
22 import org
.apache
.lucene
.index
.CorruptIndexException
;
23 import org
.apache
.lucene
.queryParser
.ParseException
;
24 import org
.apache
.lucene
.search
.TopDocs
;
25 import org
.hibernate
.criterion
.Criterion
;
26 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
27 import org
.springframework
.stereotype
.Service
;
28 import org
.springframework
.transaction
.annotation
.Propagation
;
29 import org
.springframework
.transaction
.annotation
.Transactional
;
31 import eu
.etaxonomy
.cdm
.api
.service
.config
.ITaxonServiceConfigurator
;
32 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
33 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
34 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
35 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
36 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
37 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
38 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
39 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
40 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
41 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
42 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
43 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
44 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseFieldBridge
;
45 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
46 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
47 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
48 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
49 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
50 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
51 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
52 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
53 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
54 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
55 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
56 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
57 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
58 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
59 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
60 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
61 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
62 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
63 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
64 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
65 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
66 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
67 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
68 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
69 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
70 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
71 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
72 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
73 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
74 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
75 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
76 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
77 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
78 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
79 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
80 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
81 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
82 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
83 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
84 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
85 import eu
.etaxonomy
.cdm
.search
.LuceneSearch
;
86 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
90 * @author a.kohlbecker
95 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
96 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
97 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
99 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
101 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
103 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
107 private ITaxonNameDao nameDao
;
110 private ISearchResultBuilder searchResultBuilder
;
113 private INameService nameService
;
116 private ICdmGenericDao genericDao
;
119 private IDescriptionService descriptionService
;
122 private IOrderedTermVocabularyDao orderedVocabularyDao
;
127 public TaxonServiceImpl(){
128 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
132 * FIXME Candidate for harmonization
133 * rename searchByName ?
135 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
136 return dao
.getTaxaByName(name
, sec
);
140 * FIXME Candidate for harmonization
141 * list(Synonym.class, ...)
143 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
145 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
146 return dao
.getAllSynonyms(limit
, start
);
150 * FIXME Candidate for harmonization
151 * list(Taxon.class, ...)
153 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
155 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
156 return dao
.getAllTaxa(limit
, start
);
160 * FIXME Candidate for harmonization
161 * merge with getRootTaxa(Reference sec, ..., ...)
163 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
165 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
166 if (cdmFetch
== null){
167 cdmFetch
= CdmFetch
.NO_FETCH();
169 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
174 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
176 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
177 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
181 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
183 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
184 return dao
.getAllRelationships(limit
, start
);
188 * FIXME Candidate for harmonization
189 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
192 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
194 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
195 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
196 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
197 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
198 return taxonRelTypeVocabulary
;
205 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
207 @Transactional(readOnly
= false)
208 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
210 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
211 synonymName
.removeTaxonBase(synonym
);
212 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
213 taxonName
.removeTaxonBase(acceptedTaxon
);
215 synonym
.setName(taxonName
);
216 acceptedTaxon
.setName(synonymName
);
218 // the accepted taxon needs a new uuid because the concept has changed
219 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
220 //acceptedTaxon.setUuid(UUID.randomUUID());
225 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
227 //TODO correct delete handling still needs to be implemented / checked
229 @Transactional(readOnly
= false)
230 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
232 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
233 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
234 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
236 //check synonym is not homotypic
237 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
238 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
239 throw new HomotypicalGroupChangeException(message
);
242 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
244 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
245 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
247 for (Synonym heteroSynonym
: heteroSynonyms
){
248 if (synonym
.equals(heteroSynonym
)){
249 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
251 //move synonyms in same homotypic group to new accepted taxon
252 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
256 //synonym.getName().removeTaxonBase(synonym);
257 //TODO correct delete handling still needs to be implemented / checked
259 // deleteSynonym(synonym, taxon, false);
262 this.delete(synonym
);
264 } catch (Exception e
) {
265 logger
.info("Can't delete old synonym from database");
269 return newAcceptedTaxon
;
273 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
275 // Get name from synonym
276 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
278 // remove synonym from taxon
279 toTaxon
.removeSynonym(synonym
);
281 // Create a taxon with synonym name
282 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
284 // Add taxon relation
285 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
287 // since we are swapping names, we have to detach the name from the synonym completely.
288 // Otherwise the synonym will still be in the list of typified names.
289 synonym
.getName().removeTaxonBase(synonym
);
296 * @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)
298 @Transactional(readOnly
= false)
300 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
301 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
303 TaxonNameBase synonymName
= synonym
.getName();
304 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
308 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
309 newHomotypicalGroup
.addTypifiedName(synonymName
);
311 //remove existing basionym relationships
312 synonymName
.removeBasionyms();
314 //add basionym relationship
315 if (setBasionymRelationIfApplicable
){
316 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
317 for (TaxonNameBase basionym
: basionyms
){
318 synonymName
.addBasionym(basionym
);
322 //set synonym relationship correctly
323 // SynonymRelationship relToTaxon = null;
324 boolean relToTargetTaxonExists
= false;
325 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
326 for (SynonymRelationship rel
: existingRelations
){
327 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
328 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
329 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
330 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
331 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
332 rel
.setType(newRelationType
);
333 //TODO handle citation and microCitation
336 relToTargetTaxonExists
= true;
338 if (removeFromOtherTaxa
){
339 acceptedTaxon
.removeSynonym(synonym
, false);
345 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
346 Taxon acceptedTaxon
= targetTaxon
;
347 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
348 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
349 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
350 //TODO handle citation and microCitation
351 Reference citation
= null;
352 String microCitation
= null;
353 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
360 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
363 @Transactional(readOnly
= false)
364 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
366 clazz
= TaxonBase
.class;
368 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
372 protected void setDao(ITaxonDao dao
) {
377 * @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)
379 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
380 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
382 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
383 if(numberOfResults
> 0) { // no point checking again
384 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
387 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
391 * @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)
393 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
394 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
396 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
397 if(numberOfResults
> 0) { // no point checking again
398 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
405 * @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)
407 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
408 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
410 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
411 if(numberOfResults
> 0) { // no point checking again
412 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
418 * @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)
420 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
421 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
423 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
424 if(numberOfResults
> 0) { // no point checking again
425 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
427 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
431 * @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)
433 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
434 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
436 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
437 if(numberOfResults
> 0) { // no point checking again
438 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
444 * @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)
446 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
447 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
449 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
450 if(numberOfResults
> 0) { // no point checking again
451 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
453 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
457 * @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)
459 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
460 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
462 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
463 if(numberOfResults
> 0) { // no point checking again
464 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
467 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
471 * @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)
473 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
474 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
476 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
477 if(numberOfResults
> 0) { // no point checking again
478 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
481 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
485 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
487 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
488 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
489 return t
.getHomotypicSynonymsByHomotypicGroup();
493 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
495 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
496 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
497 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
498 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
499 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
500 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
502 return heterotypicSynonymyGroups
;
505 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator
){
507 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
508 // Class<? extends TaxonBase> clazz = null;
509 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
510 // clazz = TaxonBase.class;
511 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
512 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
513 // } else if(configurator.isDoTaxa()) {
514 // clazz = Taxon.class;
515 // //propertyPath = configurator.getTaxonPropertyPath();
516 // } else if (configurator.isDoSynonyms()) {
517 // clazz = Synonym.class;
518 // //propertyPath = configurator.getSynonymPropertyPath();
522 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
527 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
529 public Pager
<IdentifiableEntity
> findTaxaAndNames(ITaxonServiceConfigurator configurator
) {
531 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
532 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
533 List
<TaxonBase
> taxa
= null;
536 long numberTaxaResults
= 0L;
539 List
<String
> propertyPath
= new ArrayList
<String
>();
540 if(configurator
.getTaxonPropertyPath() != null){
541 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
545 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
546 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
548 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
549 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
550 configurator
.getNamedAreas());
553 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
554 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
555 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
556 configurator
.getMatchMode(), configurator
.getNamedAreas(),
557 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
561 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
564 results
.addAll(taxa
);
567 numberOfResults
+= numberTaxaResults
;
569 // Names without taxa
570 if (configurator
.isDoNamesWithoutTaxa()) {
571 int numberNameResults
= 0;
573 List
<?
extends TaxonNameBase
<?
,?
>> names
=
574 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
575 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
576 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
577 if (names
.size() > 0) {
578 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
579 if (taxonName
.getTaxonBases().size() == 0) {
580 results
.add(taxonName
);
584 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
585 numberOfResults
+= numberNameResults
;
589 // Taxa from common names
591 if (configurator
.isDoTaxaByCommonNames()) {
592 taxa
= new ArrayList
<TaxonBase
>();
593 numberTaxaResults
= 0;
594 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
595 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
597 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
598 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
599 for( Object
[] entry
: commonNameResults
) {
600 taxa
.add((TaxonBase
) entry
[0]);
604 results
.addAll(taxa
);
606 numberOfResults
+= numberTaxaResults
;
610 return new DefaultPagerImpl
<IdentifiableEntity
>
611 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
614 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
615 return dao
.getUuidAndTitleCache();
619 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
621 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
622 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
623 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
624 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
625 for (TaxonDescription taxDesc
: descriptions
){
626 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
627 for (DescriptionElementBase descElem
: elements
){
628 for(Media media
: descElem
.getMedia()){
630 //find the best matching representation
631 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
640 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
642 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
643 return this.dao
.findById(listOfIDs
);
647 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
649 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
650 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
654 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
656 public int countAllRelationships() {
657 return this.dao
.countAllRelationships();
664 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
666 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
667 return this.dao
.findIdenticalTaxonNames(propertyPath
);
672 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
675 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
677 config
= new TaxonDeletionConfigurator();
681 if (! config
.isDeleteTaxonNodes()){
682 if (taxon
.getTaxonNodes().size() > 0){
683 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
684 throw new ReferencedObjectUndeletableException(message
);
689 // SynonymRelationShip
690 if (config
.isDeleteSynonymRelations()){
691 boolean removeSynonymNameFromHomotypicalGroup
= false;
692 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
693 Synonym synonym
= synRel
.getSynonym();
694 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
695 if (config
.isDeleteSynonymsIfPossible()){
697 boolean newHomotypicGroupIfNeeded
= true;
698 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
700 deleteSynonymRelationships(synonym
, taxon
);
706 if (! config
.isDeleteTaxonRelationships()){
707 if (taxon
.getTaxonRelations().size() > 0){
708 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.";
709 throw new ReferencedObjectUndeletableException(message
);
715 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
717 for (TaxonDescription desc
: descriptions
){
718 if (config
.isDeleteDescriptions()){
719 //TODO use description delete configurator ?
720 //FIXME check if description is ALWAYS deletable
721 descriptionService
.delete(desc
);
723 if (desc
.getDescribedSpecimenOrObservations().size()>0){
724 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
725 " which also describes specimens or abservations";
726 throw new ReferencedObjectUndeletableException(message
);
732 //check references with only reverse mapping
733 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
734 for (CdmBase referencingObject
: referencingObjects
){
735 //IIdentificationKeys (Media, Polytomous, MultiAccess)
736 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
737 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
738 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
739 throw new ReferencedObjectUndeletableException(message
);
744 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
745 String message
= "Taxon can't be deleted as it is used in polytomous key node";
746 throw new ReferencedObjectUndeletableException(message
);
750 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
751 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
752 throw new ReferencedObjectUndeletableException(message
);
758 if (config
.isDeleteNameIfPossible()){
760 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
761 } catch (ReferencedObjectUndeletableException e
) {
763 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
770 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
772 @Transactional(readOnly
= false)
774 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
775 if (synonym
== null){
778 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
780 //remove synonymRelationship
781 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
785 taxonSet
.addAll(synonym
.getAcceptedTaxa());
787 for (Taxon relatedTaxon
: taxonSet
){
788 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
789 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
791 this.saveOrUpdate(synonym
);
793 //TODO remove name from homotypical group?
795 //remove synonym (if necessary)
796 if (synonym
.getSynonymRelations().isEmpty()){
797 TaxonNameBase
<?
,?
> name
= synonym
.getName();
798 synonym
.setName(null);
801 //remove name if possible (and required)
802 if (name
!= null && removeNameIfPossible
){
804 nameService
.delete(name
, new NameDeletionConfigurator());
805 }catch (DataChangeNoRollbackException ex
){
806 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
814 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
816 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
818 return this.dao
.findIdenticalNamesNew(propertyPath
);
822 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
824 public String
getPhylumName(TaxonNameBase name
){
825 return this.dao
.getPhylumName(name
);
829 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
831 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
832 return dao
.deleteSynonymRelationships(syn
, taxon
);
836 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
838 public long deleteSynonymRelationships(Synonym syn
) {
839 return dao
.deleteSynonymRelationships(syn
, null);
844 * @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)
846 public List
<SynonymRelationship
> listSynonymRelationships(
847 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
848 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
849 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
851 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
852 if(numberOfResults
> 0) { // no point checking again
853 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
859 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
862 public Taxon
findBestMatchingTaxon(String taxonName
) {
863 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
864 config
.setTaxonNameTitle(taxonName
);
865 return findBestMatchingTaxon(config
);
871 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
873 Taxon bestCandidate
= null;
875 // 1. search for acceptet taxa
876 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
877 boolean bestCandidateMatchesSecUuid
= false;
878 boolean bestCandidateIsInClassification
= false;
879 int countEqualCandidates
= 0;
880 for(TaxonBase taxonBaseCandidate
: taxonList
){
881 if(taxonBaseCandidate
instanceof Taxon
){
882 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
883 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
884 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
886 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
887 bestCandidate
= newCanditate
;
888 countEqualCandidates
= 1;
889 bestCandidateMatchesSecUuid
= true;
893 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
894 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
896 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
897 bestCandidate
= newCanditate
;
898 countEqualCandidates
= 1;
899 bestCandidateIsInClassification
= true;
902 if (bestCandidate
== null){
903 bestCandidate
= newCanditate
;
904 countEqualCandidates
= 1;
908 }else{ //not Taxon.class
911 countEqualCandidates
++;
914 if (bestCandidate
!= null){
915 if(countEqualCandidates
> 1){
916 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
917 return bestCandidate
;
919 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
920 return bestCandidate
;
925 // 2. search for synonyms
926 if (config
.isIncludeSynonyms()){
927 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
928 for(TaxonBase taxonBase
: synonymList
){
929 if(taxonBase
instanceof Synonym
){
930 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
931 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
932 if(!acceptetdCandidates
.isEmpty()){
933 bestCandidate
= acceptetdCandidates
.iterator().next();
934 if(acceptetdCandidates
.size() == 1){
935 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
936 return bestCandidate
;
938 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
939 return bestCandidate
;
941 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
947 } catch (Exception e
){
951 return bestCandidate
;
954 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
955 UUID configClassificationUuid
= config
.getClassificationUuid();
956 if (configClassificationUuid
== null){
959 for (TaxonNode node
: taxon
.getTaxonNodes()){
960 UUID classUuid
= node
.getClassification().getUuid();
961 if (configClassificationUuid
.equals(classUuid
)){
968 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
969 UUID configSecUuid
= config
.getSecUuid();
970 if (configSecUuid
== null){
973 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
974 return configSecUuid
.equals(taxonSecUuid
);
978 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
981 public Synonym
findBestMatchingSynonym(String taxonName
) {
982 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
983 if(! synonymList
.isEmpty()){
984 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
985 if(synonymList
.size() == 1){
986 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
989 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
998 * @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)
1001 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1002 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1004 Synonym synonym
= oldSynonymRelation
.getSynonym();
1005 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1006 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1007 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1008 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1009 //set default relationship type
1010 if (newSynonymRelationshipType
== null){
1011 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1013 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1015 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1016 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1017 boolean isSingleInGroup
= !(hgSize
> 1);
1019 if (! isSingleInGroup
){
1020 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1021 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1022 if (isHomotypicToAccepted
){
1023 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.";
1024 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1025 message
= String
.format(message
, homotypicRelatives
);
1026 throw new HomotypicalGroupChangeException(message
);
1028 if (! moveHomotypicGroup
){
1029 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.";
1030 throw new HomotypicalGroupChangeException(message
);
1033 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1035 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1037 SynonymRelationship result
= null;
1038 //move all synonyms to new taxon
1039 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1040 for (Synonym syn
: homotypicSynonyms
){
1041 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1042 for (SynonymRelationship synRelation
: synRelations
){
1043 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1044 Reference
<?
> newReference
= reference
;
1045 if (newReference
== null && keepReference
){
1046 newReference
= synRelation
.getCitation();
1048 String newRefDetail
= referenceDetail
;
1049 if (newRefDetail
== null && keepReference
){
1050 newRefDetail
= synRelation
.getCitationMicroReference();
1052 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1053 fromTaxon
.removeSynonymRelation(synRelation
, false);
1055 //change homotypic group of synonym if relType is 'homotypic'
1056 // if (newRelTypeIsHomotypic){
1057 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1060 if (synRelation
.equals(oldSynonymRelation
)){
1061 result
= newSynRelation
;
1067 saveOrUpdate(newTaxon
);
1068 //Assert that there is a result
1069 if (result
== null){
1070 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1071 throw new IllegalStateException(message
);
1077 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1080 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1081 return dao
.getUuidAndTitleCacheTaxon();
1085 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1088 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1089 return dao
.getUuidAndTitleCacheSynonym();
1093 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1094 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1095 List
<Language
> languages
, Integer pageSize
, Integer pageNumber
,
1096 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1098 // // type selection
1099 // String typeSelect = "";
1100 // if(clazz != null){
1101 // typeSelect = "_hibernate_class:\"" + clazz.getName() + "\" AND ";
1103 Class
<?
extends DescriptionElementBase
> directorySelectClass
= DescriptionElementBase
.class;
1105 directorySelectClass
= clazz
;
1108 StringBuilder luceneQueryTemplate
= new StringBuilder();
1110 luceneQueryTemplate
.append("titleCache:%1$s ");
1111 luceneQueryTemplate
.append("name:%1$s").append(" ");
1112 // text field from TextData
1113 appendLocalizedFieldQuery("text", languages
, luceneQueryTemplate
).append(" ");
1114 // state field from CategoricalData
1115 appendLocalizedFieldQuery("states.state.representation", languages
, luceneQueryTemplate
).append(" ");
1116 // state field from CategoricalData
1117 appendLocalizedFieldQuery("states.modifyingText", languages
, luceneQueryTemplate
).append(" ");
1119 // String luceneQueryTemplate = typeSelect + "( titleCache:%1$s OR " + languageSelection + "OR name:%1$s )";
1120 String luceneQuery
= String
.format(luceneQueryTemplate
.toString(), queryString
);
1122 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), directorySelectClass
);
1123 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(luceneQuery
, clazz
);
1124 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSetFromIds(luceneSearch
, topDocsResultSet
, dao
, "inDescription.taxon.id");
1126 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
1131 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseFieldBridge}
1132 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1133 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1135 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseFieldBridge}
1136 * or {@link MultilanguageTextFieldBridge }
1137 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1138 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1139 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1141 * TODO move to utiliy class !!!!!!!!
1143 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1145 if(stringBuilder
== null){
1146 stringBuilder
= new StringBuilder();
1148 if(languages
== null || languages
.size() == 0){
1149 stringBuilder
.append(name
+ ".ALL:%1$s ");
1151 for(Language lang
: languages
){
1152 stringBuilder
.append(name
+ "." + lang
.getLabel() + ":%1$s ");
1155 return stringBuilder
;
1158 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1159 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1160 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1162 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1165 UUID uuid
= taxon
.getName().getUuid();
1166 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1167 String epithetOfTaxon
= null;
1168 String infragenericEpithetOfTaxon
= null;
1169 String infraspecificEpithetOfTaxon
= null;
1170 if (taxonName
.isSpecies()){
1171 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1172 } else if (taxonName
.isInfraGeneric()){
1173 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1174 } else if (taxonName
.isInfraSpecific()){
1175 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1177 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1178 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1179 List
<String
> taxonNames
= new ArrayList
<String
>();
1181 for (TaxonNode node
: nodes
){
1182 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1183 // List<String> synonymsEpithet = new ArrayList<String>();
1185 if (node
.getClassification().equals(classification
)){
1186 if (!node
.isTopmostNode()){
1187 TaxonNode parent
= (TaxonNode
)node
.getParent();
1188 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1189 TaxonNameBase parentName
= parent
.getTaxon().getName();
1190 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1191 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1192 Rank rankOfTaxon
= taxonName
.getRank();
1195 //create inferred synonyms for species, subspecies
1196 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1198 Synonym inferredEpithet
= null;
1199 Synonym inferredGenus
= null;
1200 Synonym potentialCombination
= null;
1202 List
<String
> propertyPaths
= new ArrayList
<String
>();
1203 propertyPaths
.add("synonym");
1204 propertyPaths
.add("synonym.name");
1205 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1206 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1208 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1209 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1211 List
<TaxonRelationship
> taxonRelListParent
= null;
1212 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1213 if (doWithMisappliedNames
){
1214 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1215 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1219 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1220 Set
<String
> genusNames
= new HashSet
<String
>();
1222 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1223 Synonym syn
= synonymRelationOfParent
.getSynonym();
1225 inferredEpithet
= createInferredEpithets(taxon
,
1226 zooHashMap
, taxonName
, epithetOfTaxon
,
1227 infragenericEpithetOfTaxon
,
1228 infraspecificEpithetOfTaxon
,
1229 taxonNames
, parentName
,
1233 inferredSynonyms
.add(inferredEpithet
);
1234 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1235 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1238 if (doWithMisappliedNames
){
1240 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1241 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1243 inferredEpithet
= createInferredEpithets(taxon
,
1244 zooHashMap
, taxonName
, epithetOfTaxon
,
1245 infragenericEpithetOfTaxon
,
1246 infraspecificEpithetOfTaxon
,
1247 taxonNames
, parentName
,
1250 inferredSynonyms
.add(inferredEpithet
);
1251 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1252 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1256 if (!taxonNames
.isEmpty()){
1257 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1258 ZoologicalName name
;
1259 if (!synNotInCDM
.isEmpty()){
1260 inferredSynonymsToBeRemoved
.clear();
1262 for (Synonym syn
:inferredSynonyms
){
1263 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1264 if (!synNotInCDM
.contains(name
.getNameCache())){
1265 inferredSynonymsToBeRemoved
.add(syn
);
1269 // Remove identified Synonyms from inferredSynonyms
1270 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1271 inferredSynonyms
.remove(synonym
);
1276 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1279 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1280 TaxonNameBase synName
;
1281 ZoologicalName inferredSynName
;
1283 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1284 inferredGenus
= createInferredGenus(taxon
,
1285 zooHashMap
, taxonName
, epithetOfTaxon
,
1286 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1288 inferredSynonyms
.add(inferredGenus
);
1289 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1290 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1295 if (doWithMisappliedNames
){
1297 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1298 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1299 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1301 inferredSynonyms
.add(inferredGenus
);
1302 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1303 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1308 if (!taxonNames
.isEmpty()){
1309 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1310 ZoologicalName name
;
1311 if (!synNotInCDM
.isEmpty()){
1312 inferredSynonymsToBeRemoved
.clear();
1314 for (Synonym syn
:inferredSynonyms
){
1315 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1316 if (!synNotInCDM
.contains(name
.getNameCache())){
1317 inferredSynonymsToBeRemoved
.add(syn
);
1321 // Remove identified Synonyms from inferredSynonyms
1322 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1323 inferredSynonyms
.remove(synonym
);
1328 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1330 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1331 ZoologicalName inferredSynName
;
1332 //for all synonyms of the parent...
1333 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1334 TaxonNameBase synName
;
1335 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1336 synName
= synParent
.getName();
1338 HibernateProxyHelper
.deproxy(synParent
);
1340 // Set the sourceReference
1341 sourceReference
= synParent
.getSec();
1343 // Determine the idInSource
1344 String idInSourceParent
= getIdInSource(synParent
);
1346 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1347 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1348 String synParentInfragenericName
= null;
1349 String synParentSpecificEpithet
= null;
1351 if (parentSynZooName
.isInfraGeneric()){
1352 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1354 if (parentSynZooName
.isSpecies()){
1355 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1358 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1359 synonymsGenus.put(synGenusName, idInSource);
1362 //for all synonyms of the taxon
1364 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1366 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1367 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1368 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1370 synParentInfragenericName
,
1371 synParentSpecificEpithet
, syn
, zooHashMap
);
1373 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1374 inferredSynonyms
.add(potentialCombination
);
1375 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1376 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1383 if (doWithMisappliedNames
){
1385 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1387 TaxonNameBase misappliedParentName
;
1389 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1390 misappliedParentName
= misappliedParent
.getName();
1392 HibernateProxyHelper
.deproxy(misappliedParent
);
1394 // Set the sourceReference
1395 sourceReference
= misappliedParent
.getSec();
1397 // Determine the idInSource
1398 String idInSourceParent
= getIdInSource(misappliedParent
);
1400 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1401 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1402 String synParentInfragenericName
= null;
1403 String synParentSpecificEpithet
= null;
1405 if (parentSynZooName
.isInfraGeneric()){
1406 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1408 if (parentSynZooName
.isSpecies()){
1409 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1413 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1414 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1415 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1416 potentialCombination
= createPotentialCombination(
1417 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1419 synParentInfragenericName
,
1420 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1423 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1424 inferredSynonyms
.add(potentialCombination
);
1425 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1426 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1431 if (!taxonNames
.isEmpty()){
1432 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1433 ZoologicalName name
;
1434 if (!synNotInCDM
.isEmpty()){
1435 inferredSynonymsToBeRemoved
.clear();
1436 for (Synonym syn
:inferredSynonyms
){
1438 name
= (ZoologicalName
) syn
.getName();
1439 }catch (ClassCastException e
){
1440 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1442 if (!synNotInCDM
.contains(name
.getNameCache())){
1443 inferredSynonymsToBeRemoved
.add(syn
);
1446 // Remove identified Synonyms from inferredSynonyms
1447 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1448 inferredSynonyms
.remove(synonym
);
1454 logger
.info("The synonymrelationship type is not defined.");
1455 return inferredSynonyms
;
1462 return inferredSynonyms
;
1465 private Synonym
createPotentialCombination(String idInSourceParent
,
1466 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1467 String synParentInfragenericName
, String synParentSpecificEpithet
,
1468 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1469 Synonym potentialCombination
;
1470 Reference sourceReference
;
1471 ZoologicalName inferredSynName
;
1472 HibernateProxyHelper
.deproxy(syn
);
1474 // Set sourceReference
1475 sourceReference
= syn
.getSec();
1478 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1480 String synTaxonInfraSpecificName
= null;
1482 if (parentSynZooName
.isSpecies()){
1483 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1486 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1487 synonymsEpithet.add(epithetName);
1490 //create potential combinations...
1491 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1493 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1494 if (zooSynName
.isSpecies()){
1495 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1496 if (parentSynZooName
.isInfraGeneric()){
1497 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1500 if (zooSynName
.isInfraSpecific()){
1501 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1502 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1504 if (parentSynZooName
.isInfraGeneric()){
1505 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1509 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1511 // Set the sourceReference
1512 potentialCombination
.setSec(sourceReference
);
1515 // Determine the idInSource
1516 String idInSourceSyn
= getIdInSource(syn
);
1518 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1519 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1520 inferredSynName
.addSource(originalSource
);
1521 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1522 potentialCombination
.addSource(originalSource
);
1525 inferredSynName
.generateTitle();
1527 return potentialCombination
;
1530 private Synonym
createInferredGenus(Taxon taxon
,
1531 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1532 String epithetOfTaxon
, String genusOfTaxon
,
1533 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1536 Synonym inferredGenus
;
1537 TaxonNameBase synName
;
1538 ZoologicalName inferredSynName
;
1539 synName
=syn
.getName();
1540 HibernateProxyHelper
.deproxy(syn
);
1542 // Determine the idInSource
1543 String idInSourceSyn
= getIdInSource(syn
);
1544 String idInSourceTaxon
= getIdInSource(taxon
);
1545 // Determine the sourceReference
1546 Reference sourceReference
= syn
.getSec();
1548 synName
= syn
.getName();
1549 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1550 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1551 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1552 synonymsEpithet.add(synSpeciesEpithetName);
1555 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1556 //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...
1559 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1560 if (zooParentName
.isInfraGeneric()){
1561 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1564 if (taxonName
.isSpecies()){
1565 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1567 if (taxonName
.isInfraSpecific()){
1568 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1569 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1573 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1575 // Set the sourceReference
1576 inferredGenus
.setSec(sourceReference
);
1578 // Add the original source
1579 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1580 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1581 inferredGenus
.addSource(originalSource
);
1583 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1584 inferredSynName
.addSource(originalSource
);
1588 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1590 inferredSynName
.generateTitle();
1593 return inferredGenus
;
1596 private Synonym
createInferredEpithets(Taxon taxon
,
1597 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1598 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1599 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1600 TaxonNameBase parentName
, TaxonBase syn
) {
1602 Synonym inferredEpithet
;
1603 TaxonNameBase synName
;
1604 ZoologicalName inferredSynName
;
1605 HibernateProxyHelper
.deproxy(syn
);
1607 // Determine the idInSource
1608 String idInSourceSyn
= getIdInSource(syn
);
1609 String idInSourceTaxon
= getIdInSource(taxon
);
1610 // Determine the sourceReference
1611 Reference sourceReference
= syn
.getSec();
1613 synName
= syn
.getName();
1614 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1615 String synGenusName
= zooSynName
.getGenusOrUninomial();
1616 String synInfraGenericEpithet
= null;
1617 String synSpecificEpithet
= null;
1619 if (zooSynName
.getInfraGenericEpithet() != null){
1620 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1623 if (zooSynName
.isInfraSpecific()){
1624 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1627 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1628 synonymsGenus.put(synGenusName, idInSource);
1631 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1633 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1634 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1635 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1637 inferredSynName
.setGenusOrUninomial(synGenusName
);
1639 if (parentName
.isInfraGeneric()){
1640 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1642 if (taxonName
.isSpecies()){
1643 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1644 }else if (taxonName
.isInfraSpecific()){
1645 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1646 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1649 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1651 // Set the sourceReference
1652 inferredEpithet
.setSec(sourceReference
);
1654 /* Add the original source
1655 if (idInSource != null) {
1656 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1659 Reference citation = getCitation(syn);
1660 if (citation != null) {
1661 originalSource.setCitation(citation);
1662 inferredEpithet.addSource(originalSource);
1665 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1667 IdentifiableSource originalSource
;
1668 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1670 inferredEpithet
.addSource(originalSource
);
1672 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1674 inferredSynName
.addSource(originalSource
);
1678 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1680 inferredSynName
.generateTitle();
1681 return inferredEpithet
;
1685 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1686 * Very likely only useful for createInferredSynonyms().
1691 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1692 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1693 if (taxonName
== null) {
1694 taxonName
= zooHashMap
.get(uuid
);
1700 * Returns the idInSource for a given Synonym.
1703 private String
getIdInSource(TaxonBase taxonBase
) {
1704 String idInSource
= null;
1705 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1706 if (sources
.size() == 1) {
1707 IdentifiableSource source
= sources
.iterator().next();
1708 if (source
!= null) {
1709 idInSource
= source
.getIdInSource();
1711 } else if (sources
.size() > 1) {
1714 for (IdentifiableSource source
: sources
) {
1715 idInSource
+= source
.getIdInSource();
1716 if (count
< sources
.size()) {
1728 * Returns the citation for a given Synonym.
1731 private Reference
getCitation(Synonym syn
) {
1732 Reference citation
= null;
1733 Set
<IdentifiableSource
> sources
= syn
.getSources();
1734 if (sources
.size() == 1) {
1735 IdentifiableSource source
= sources
.iterator().next();
1736 if (source
!= null) {
1737 citation
= source
.getCitation();
1739 } else if (sources
.size() > 1) {
1740 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1746 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1747 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1749 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1750 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1751 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1753 return inferredSynonyms
;