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