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
.BooleanClause
.Occur
;
25 import org
.apache
.lucene
.search
.BooleanQuery
;
26 import org
.apache
.lucene
.search
.Query
;
27 import org
.apache
.lucene
.search
.SortField
;
28 import org
.apache
.lucene
.search
.TopDocs
;
29 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
30 import org
.springframework
.stereotype
.Service
;
31 import org
.springframework
.transaction
.annotation
.Propagation
;
32 import org
.springframework
.transaction
.annotation
.Transactional
;
34 import eu
.etaxonomy
.cdm
.api
.service
.config
.IFindTaxaAndNamesConfigurator
;
35 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
36 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
37 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
38 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
39 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
40 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
41 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
42 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
43 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
44 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
45 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
48 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
49 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
50 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
51 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
52 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
53 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
54 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
55 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
56 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
57 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
58 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
59 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
60 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
61 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
62 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
63 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
64 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
65 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
66 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
67 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
68 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
69 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
70 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
71 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
72 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
73 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
74 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
75 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
76 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
77 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
78 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
79 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
80 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
81 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
82 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
83 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
84 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
85 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
86 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
87 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
88 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
89 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
90 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
91 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
92 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
96 * @author a.kohlbecker
101 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
102 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
103 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
105 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
107 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
109 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
113 private ITaxonNameDao nameDao
;
116 private INameService nameService
;
119 private ICdmGenericDao genericDao
;
122 private IDescriptionService descriptionService
;
125 private IOrderedTermVocabularyDao orderedVocabularyDao
;
130 public TaxonServiceImpl(){
131 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
135 * FIXME Candidate for harmonization
136 * rename searchByName ?
138 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
139 return dao
.getTaxaByName(name
, sec
);
143 * FIXME Candidate for harmonization
144 * list(Synonym.class, ...)
146 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
148 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
149 return dao
.getAllSynonyms(limit
, start
);
153 * FIXME Candidate for harmonization
154 * list(Taxon.class, ...)
156 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
158 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
159 return dao
.getAllTaxa(limit
, start
);
163 * FIXME Candidate for harmonization
164 * merge with getRootTaxa(Reference sec, ..., ...)
166 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
168 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
169 if (cdmFetch
== null){
170 cdmFetch
= CdmFetch
.NO_FETCH();
172 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
177 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
179 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
180 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
184 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
186 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
187 return dao
.getAllRelationships(limit
, start
);
191 * FIXME Candidate for harmonization
192 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
195 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
197 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
198 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
199 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
200 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
201 return taxonRelTypeVocabulary
;
208 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
210 @Transactional(readOnly
= false)
211 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
213 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
214 synonymName
.removeTaxonBase(synonym
);
215 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
216 taxonName
.removeTaxonBase(acceptedTaxon
);
218 synonym
.setName(taxonName
);
219 acceptedTaxon
.setName(synonymName
);
221 // the accepted taxon needs a new uuid because the concept has changed
222 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
223 //acceptedTaxon.setUuid(UUID.randomUUID());
228 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
230 //TODO correct delete handling still needs to be implemented / checked
232 @Transactional(readOnly
= false)
233 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
235 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
236 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
237 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
239 //check synonym is not homotypic
240 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
241 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
242 throw new HomotypicalGroupChangeException(message
);
245 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
247 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
248 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
250 for (Synonym heteroSynonym
: heteroSynonyms
){
251 if (synonym
.equals(heteroSynonym
)){
252 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
254 //move synonyms in same homotypic group to new accepted taxon
255 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
259 //synonym.getName().removeTaxonBase(synonym);
260 //TODO correct delete handling still needs to be implemented / checked
262 // deleteSynonym(synonym, taxon, false);
265 this.delete(synonym
);
267 } catch (Exception e
) {
268 logger
.info("Can't delete old synonym from database");
272 return newAcceptedTaxon
;
276 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
278 // Get name from synonym
279 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
281 // remove synonym from taxon
282 toTaxon
.removeSynonym(synonym
);
284 // Create a taxon with synonym name
285 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
287 // Add taxon relation
288 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
290 // since we are swapping names, we have to detach the name from the synonym completely.
291 // Otherwise the synonym will still be in the list of typified names.
292 synonym
.getName().removeTaxonBase(synonym
);
299 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeHomotypicalGroupOfSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.name.HomotypicalGroup, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
301 @Transactional(readOnly
= false)
303 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
304 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
306 TaxonNameBase synonymName
= synonym
.getName();
307 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
311 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
312 newHomotypicalGroup
.addTypifiedName(synonymName
);
314 //remove existing basionym relationships
315 synonymName
.removeBasionyms();
317 //add basionym relationship
318 if (setBasionymRelationIfApplicable
){
319 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
320 for (TaxonNameBase basionym
: basionyms
){
321 synonymName
.addBasionym(basionym
);
325 //set synonym relationship correctly
326 // SynonymRelationship relToTaxon = null;
327 boolean relToTargetTaxonExists
= false;
328 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
329 for (SynonymRelationship rel
: existingRelations
){
330 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
331 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
332 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
333 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
334 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
335 rel
.setType(newRelationType
);
336 //TODO handle citation and microCitation
339 relToTargetTaxonExists
= true;
341 if (removeFromOtherTaxa
){
342 acceptedTaxon
.removeSynonym(synonym
, false);
348 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
349 Taxon acceptedTaxon
= targetTaxon
;
350 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
351 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
352 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
353 //TODO handle citation and microCitation
354 Reference citation
= null;
355 String microCitation
= null;
356 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
363 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
366 @Transactional(readOnly
= false)
367 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
369 clazz
= TaxonBase
.class;
371 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
375 protected void setDao(ITaxonDao dao
) {
380 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)
382 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
383 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
385 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
386 if(numberOfResults
> 0) { // no point checking again
387 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
390 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
394 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxaByName(java.lang.Class, java.lang.String, java.lang.String, java.lang.String, java.lang.String, eu.etaxonomy.cdm.model.name.Rank, java.lang.Integer, java.lang.Integer)
396 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
397 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
399 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
400 if(numberOfResults
> 0) { // no point checking again
401 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
408 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
410 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
411 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
413 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
414 if(numberOfResults
> 0) { // no point checking again
415 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
421 * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageToTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
423 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
424 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
426 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
427 if(numberOfResults
> 0) { // no point checking again
428 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
430 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
434 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
436 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
437 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
439 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
440 if(numberOfResults
> 0) { // no point checking again
441 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
447 * @see eu.etaxonomy.cdm.api.service.ITaxonService#pageFromTaxonRelationships(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
449 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
450 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
452 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
453 if(numberOfResults
> 0) { // no point checking again
454 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
456 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
460 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
462 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
463 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
465 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
466 if(numberOfResults
> 0) { // no point checking again
467 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
470 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
474 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getSynonyms(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
476 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
477 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
479 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
480 if(numberOfResults
> 0) { // no point checking again
481 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
484 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
488 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
490 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
491 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
492 return t
.getHomotypicSynonymsByHomotypicGroup();
496 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
498 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
499 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
500 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
501 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
502 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
503 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
505 return heterotypicSynonymyGroups
;
508 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
510 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
511 // Class<? extends TaxonBase> clazz = null;
512 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
513 // clazz = TaxonBase.class;
514 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
515 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
516 // } else if(configurator.isDoTaxa()) {
517 // clazz = Taxon.class;
518 // //propertyPath = configurator.getTaxonPropertyPath();
519 // } else if (configurator.isDoSynonyms()) {
520 // clazz = Synonym.class;
521 // //propertyPath = configurator.getSynonymPropertyPath();
525 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
530 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
532 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
534 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
535 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
536 List
<TaxonBase
> taxa
= null;
539 long numberTaxaResults
= 0L;
542 List
<String
> propertyPath
= new ArrayList
<String
>();
543 if(configurator
.getTaxonPropertyPath() != null){
544 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
548 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
549 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
551 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
552 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
553 configurator
.getNamedAreas());
556 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
557 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
558 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
559 configurator
.getMatchMode(), configurator
.getNamedAreas(),
560 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
564 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
567 results
.addAll(taxa
);
570 numberOfResults
+= numberTaxaResults
;
572 // Names without taxa
573 if (configurator
.isDoNamesWithoutTaxa()) {
574 int numberNameResults
= 0;
576 List
<?
extends TaxonNameBase
<?
,?
>> names
=
577 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
578 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
579 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
580 if (names
.size() > 0) {
581 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
582 if (taxonName
.getTaxonBases().size() == 0) {
583 results
.add(taxonName
);
587 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
588 numberOfResults
+= numberNameResults
;
592 // Taxa from common names
594 if (configurator
.isDoTaxaByCommonNames()) {
595 taxa
= new ArrayList
<TaxonBase
>();
596 numberTaxaResults
= 0;
597 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
598 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
600 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
601 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
602 for( Object
[] entry
: commonNameResults
) {
603 taxa
.add((TaxonBase
) entry
[0]);
607 results
.addAll(taxa
);
609 numberOfResults
+= numberTaxaResults
;
613 return new DefaultPagerImpl
<IdentifiableEntity
>
614 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
617 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
618 return dao
.getUuidAndTitleCache();
622 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
624 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
625 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
626 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
627 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
628 for (TaxonDescription taxDesc
: descriptions
){
629 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
630 for (DescriptionElementBase descElem
: elements
){
631 for(Media media
: descElem
.getMedia()){
633 //find the best matching representation
634 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
643 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
645 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, boolean limitToGalleries
, List
<String
> propertyPath
){
647 Pager
<TaxonDescription
> p
=
648 descriptionService
.getTaxonDescriptions(taxon
, null, null, null, null, propertyPath
);
650 // pars the media and quality parameters
653 // collect all media of the given taxon
654 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
655 List
<Media
> taxonGalleryMedia
= new ArrayList
<Media
>();
656 for(TaxonDescription desc
: p
.getRecords()){
658 if(desc
.isImageGallery()){
659 for(DescriptionElementBase element
: desc
.getElements()){
660 for(Media media
: element
.getMedia()){
661 taxonGalleryMedia
.add(media
);
664 } else if(!limitToGalleries
){
665 for(DescriptionElementBase element
: desc
.getElements()){
666 for(Media media
: element
.getMedia()){
667 taxonMedia
.add(media
);
674 taxonGalleryMedia
.addAll(taxonMedia
);
675 return taxonGalleryMedia
;
679 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
681 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
682 return this.dao
.findById(listOfIDs
);
686 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
688 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
689 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
693 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
695 public int countAllRelationships() {
696 return this.dao
.countAllRelationships();
703 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
705 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
706 return this.dao
.findIdenticalTaxonNames(propertyPath
);
711 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
714 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
716 config
= new TaxonDeletionConfigurator();
720 if (! config
.isDeleteTaxonNodes()){
721 if (taxon
.getTaxonNodes().size() > 0){
722 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
723 throw new ReferencedObjectUndeletableException(message
);
728 // SynonymRelationShip
729 if (config
.isDeleteSynonymRelations()){
730 boolean removeSynonymNameFromHomotypicalGroup
= false;
731 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
732 Synonym synonym
= synRel
.getSynonym();
733 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
734 if (config
.isDeleteSynonymsIfPossible()){
736 boolean newHomotypicGroupIfNeeded
= true;
737 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
739 deleteSynonymRelationships(synonym
, taxon
);
745 if (! config
.isDeleteTaxonRelationships()){
746 if (taxon
.getTaxonRelations().size() > 0){
747 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.";
748 throw new ReferencedObjectUndeletableException(message
);
754 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
756 for (TaxonDescription desc
: descriptions
){
757 if (config
.isDeleteDescriptions()){
758 //TODO use description delete configurator ?
759 //FIXME check if description is ALWAYS deletable
760 descriptionService
.delete(desc
);
762 if (desc
.getDescribedSpecimenOrObservations().size()>0){
763 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
764 " which also describes specimens or abservations";
765 throw new ReferencedObjectUndeletableException(message
);
771 //check references with only reverse mapping
772 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
773 for (CdmBase referencingObject
: referencingObjects
){
774 //IIdentificationKeys (Media, Polytomous, MultiAccess)
775 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
776 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
777 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
778 throw new ReferencedObjectUndeletableException(message
);
783 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
784 String message
= "Taxon can't be deleted as it is used in polytomous key node";
785 throw new ReferencedObjectUndeletableException(message
);
789 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
790 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
791 throw new ReferencedObjectUndeletableException(message
);
797 if (config
.isDeleteNameIfPossible()){
799 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
800 } catch (ReferencedObjectUndeletableException e
) {
802 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
809 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
811 @Transactional(readOnly
= false)
813 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
814 if (synonym
== null){
817 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
819 //remove synonymRelationship
820 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
824 taxonSet
.addAll(synonym
.getAcceptedTaxa());
826 for (Taxon relatedTaxon
: taxonSet
){
827 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
828 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
830 this.saveOrUpdate(synonym
);
832 //TODO remove name from homotypical group?
834 //remove synonym (if necessary)
835 if (synonym
.getSynonymRelations().isEmpty()){
836 TaxonNameBase
<?
,?
> name
= synonym
.getName();
837 synonym
.setName(null);
840 //remove name if possible (and required)
841 if (name
!= null && removeNameIfPossible
){
843 nameService
.delete(name
, new NameDeletionConfigurator());
844 }catch (DataChangeNoRollbackException ex
){
845 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
853 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
855 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
857 return this.dao
.findIdenticalNamesNew(propertyPath
);
861 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
863 public String
getPhylumName(TaxonNameBase name
){
864 return this.dao
.getPhylumName(name
);
868 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
870 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
871 return dao
.deleteSynonymRelationships(syn
, taxon
);
875 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
877 public long deleteSynonymRelationships(Synonym syn
) {
878 return dao
.deleteSynonymRelationships(syn
, null);
883 * @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)
885 public List
<SynonymRelationship
> listSynonymRelationships(
886 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
887 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
888 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
890 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
891 if(numberOfResults
> 0) { // no point checking again
892 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
898 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
901 public Taxon
findBestMatchingTaxon(String taxonName
) {
902 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
903 config
.setTaxonNameTitle(taxonName
);
904 return findBestMatchingTaxon(config
);
910 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
912 Taxon bestCandidate
= null;
914 // 1. search for acceptet taxa
915 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
916 boolean bestCandidateMatchesSecUuid
= false;
917 boolean bestCandidateIsInClassification
= false;
918 int countEqualCandidates
= 0;
919 for(TaxonBase taxonBaseCandidate
: taxonList
){
920 if(taxonBaseCandidate
instanceof Taxon
){
921 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
922 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
923 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
925 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
926 bestCandidate
= newCanditate
;
927 countEqualCandidates
= 1;
928 bestCandidateMatchesSecUuid
= true;
932 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
933 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
935 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
936 bestCandidate
= newCanditate
;
937 countEqualCandidates
= 1;
938 bestCandidateIsInClassification
= true;
941 if (bestCandidate
== null){
942 bestCandidate
= newCanditate
;
943 countEqualCandidates
= 1;
947 }else{ //not Taxon.class
950 countEqualCandidates
++;
953 if (bestCandidate
!= null){
954 if(countEqualCandidates
> 1){
955 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
956 return bestCandidate
;
958 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
959 return bestCandidate
;
964 // 2. search for synonyms
965 if (config
.isIncludeSynonyms()){
966 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
967 for(TaxonBase taxonBase
: synonymList
){
968 if(taxonBase
instanceof Synonym
){
969 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
970 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
971 if(!acceptetdCandidates
.isEmpty()){
972 bestCandidate
= acceptetdCandidates
.iterator().next();
973 if(acceptetdCandidates
.size() == 1){
974 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
975 return bestCandidate
;
977 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
978 return bestCandidate
;
980 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
986 } catch (Exception e
){
990 return bestCandidate
;
993 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
994 UUID configClassificationUuid
= config
.getClassificationUuid();
995 if (configClassificationUuid
== null){
998 for (TaxonNode node
: taxon
.getTaxonNodes()){
999 UUID classUuid
= node
.getClassification().getUuid();
1000 if (configClassificationUuid
.equals(classUuid
)){
1007 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1008 UUID configSecUuid
= config
.getSecUuid();
1009 if (configSecUuid
== null){
1012 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1013 return configSecUuid
.equals(taxonSecUuid
);
1017 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1020 public Synonym
findBestMatchingSynonym(String taxonName
) {
1021 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1022 if(! synonymList
.isEmpty()){
1023 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1024 if(synonymList
.size() == 1){
1025 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1028 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1037 * @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)
1040 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1041 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1043 Synonym synonym
= oldSynonymRelation
.getSynonym();
1044 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1045 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1046 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1047 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1048 //set default relationship type
1049 if (newSynonymRelationshipType
== null){
1050 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1052 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1054 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1055 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1056 boolean isSingleInGroup
= !(hgSize
> 1);
1058 if (! isSingleInGroup
){
1059 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1060 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1061 if (isHomotypicToAccepted
){
1062 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.";
1063 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1064 message
= String
.format(message
, homotypicRelatives
);
1065 throw new HomotypicalGroupChangeException(message
);
1067 if (! moveHomotypicGroup
){
1068 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.";
1069 throw new HomotypicalGroupChangeException(message
);
1072 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1074 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1076 SynonymRelationship result
= null;
1077 //move all synonyms to new taxon
1078 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1079 for (Synonym syn
: homotypicSynonyms
){
1080 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1081 for (SynonymRelationship synRelation
: synRelations
){
1082 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1083 Reference
<?
> newReference
= reference
;
1084 if (newReference
== null && keepReference
){
1085 newReference
= synRelation
.getCitation();
1087 String newRefDetail
= referenceDetail
;
1088 if (newRefDetail
== null && keepReference
){
1089 newRefDetail
= synRelation
.getCitationMicroReference();
1091 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1092 fromTaxon
.removeSynonymRelation(synRelation
, false);
1094 //change homotypic group of synonym if relType is 'homotypic'
1095 // if (newRelTypeIsHomotypic){
1096 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1099 if (synRelation
.equals(oldSynonymRelation
)){
1100 result
= newSynRelation
;
1106 saveOrUpdate(newTaxon
);
1107 //Assert that there is a result
1108 if (result
== null){
1109 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1110 throw new IllegalStateException(message
);
1116 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1119 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1120 return dao
.getUuidAndTitleCacheTaxon();
1124 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1127 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1128 return dao
.getUuidAndTitleCacheSynonym();
1132 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1133 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1134 Classification classification
, List
<Language
> languages
,
1135 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1137 // // -- set defaults
1138 // Class<? extends TaxonBase> directorySelectClass = TaxonBase.class;
1139 // if(clazz != null){
1140 // directorySelectClass = clazz;
1147 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1148 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1149 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1150 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1153 Class
<?
extends DescriptionElementBase
> directorySelectClass
= DescriptionElementBase
.class;
1155 directorySelectClass
= clazz
;
1159 BooleanQuery finalQuery
= new BooleanQuery();
1160 BooleanQuery textQuery
= new BooleanQuery();
1162 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), directorySelectClass
);
1163 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1165 // ---- search criteria
1166 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1170 if(languages
== null || languages
.size() == 0){
1171 nameQuery
= queryFactory
.newTermQuery("name", queryString
);
1173 nameQuery
= new BooleanQuery();
1174 BooleanQuery languageSubQuery
= new BooleanQuery();
1175 for(Language lang
: languages
){
1176 languageSubQuery
.add(queryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString()), Occur
.SHOULD
);
1178 ((BooleanQuery
) nameQuery
).add(queryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
1179 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1181 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1184 // text field from TextData
1185 textQuery
.add(queryFactory
.newLocalizedTermQuery("text", queryString
, languages
), Occur
.SHOULD
);
1187 // --- TermBase fields - by representation ----
1188 // state field from CategoricalData
1189 textQuery
.add(queryFactory
.newLocalizedTermQuery("states.state.representation", queryString
, languages
), Occur
.SHOULD
);
1191 // state field from CategoricalData
1192 textQuery
.add(queryFactory
.newLocalizedTermQuery("states.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1194 finalQuery
.add(textQuery
, Occur
.MUST
);
1195 // --- classification ----
1197 if(classification
!= null){
1198 finalQuery
.add(queryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
1201 // --- IdentifieableEntity fields - by uuid
1202 if(features
!= null && features
.size() > 0 ){
1203 finalQuery
.add(queryFactory
.newEntityUuidQuery("feature.uuid", features
), Occur
.MUST
);
1206 // the description must be associated with a taxon
1207 finalQuery
.add(queryFactory
.newIdNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
1209 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", false)};
1211 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(finalQuery
, clazz
, pageSize
, pageNumber
, sortFields
);
1213 String
[] highlightFields
= null;
1214 if(highlightFragments
){
1215 highlightFields
= queryFactory
.getTextFieldNames().toArray(new String
[queryFactory
.getTextFieldNames().size()]);
1218 // initialize taxa, thighlight matches ....
1219 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, finalQuery
);
1220 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1221 topDocsResultSet
, highlightFields
, dao
, "inDescription.taxon.id", propertyPaths
);
1223 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
1228 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1229 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1230 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1232 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1233 * or {@link MultilanguageTextFieldBridge }
1234 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1235 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1236 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1238 * TODO move to utiliy class !!!!!!!!
1240 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1242 if(stringBuilder
== null){
1243 stringBuilder
= new StringBuilder();
1245 if(languages
== null || languages
.size() == 0){
1246 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
1248 for(Language lang
: languages
){
1249 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
1252 return stringBuilder
;
1255 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1256 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1257 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1259 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1262 UUID uuid
= taxon
.getName().getUuid();
1263 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1264 String epithetOfTaxon
= null;
1265 String infragenericEpithetOfTaxon
= null;
1266 String infraspecificEpithetOfTaxon
= null;
1267 if (taxonName
.isSpecies()){
1268 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1269 } else if (taxonName
.isInfraGeneric()){
1270 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1271 } else if (taxonName
.isInfraSpecific()){
1272 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1274 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1275 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1276 List
<String
> taxonNames
= new ArrayList
<String
>();
1278 for (TaxonNode node
: nodes
){
1279 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1280 // List<String> synonymsEpithet = new ArrayList<String>();
1282 if (node
.getClassification().equals(classification
)){
1283 if (!node
.isTopmostNode()){
1284 TaxonNode parent
= (TaxonNode
)node
.getParent();
1285 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1286 TaxonNameBase parentName
= parent
.getTaxon().getName();
1287 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1288 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1289 Rank rankOfTaxon
= taxonName
.getRank();
1292 //create inferred synonyms for species, subspecies
1293 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1295 Synonym inferredEpithet
= null;
1296 Synonym inferredGenus
= null;
1297 Synonym potentialCombination
= null;
1299 List
<String
> propertyPaths
= new ArrayList
<String
>();
1300 propertyPaths
.add("synonym");
1301 propertyPaths
.add("synonym.name");
1302 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1303 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1305 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1306 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1308 List
<TaxonRelationship
> taxonRelListParent
= null;
1309 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1310 if (doWithMisappliedNames
){
1311 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1312 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1316 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1317 Set
<String
> genusNames
= new HashSet
<String
>();
1319 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1320 Synonym syn
= synonymRelationOfParent
.getSynonym();
1322 inferredEpithet
= createInferredEpithets(taxon
,
1323 zooHashMap
, taxonName
, epithetOfTaxon
,
1324 infragenericEpithetOfTaxon
,
1325 infraspecificEpithetOfTaxon
,
1326 taxonNames
, parentName
,
1330 inferredSynonyms
.add(inferredEpithet
);
1331 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1332 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1335 if (doWithMisappliedNames
){
1337 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1338 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1340 inferredEpithet
= createInferredEpithets(taxon
,
1341 zooHashMap
, taxonName
, epithetOfTaxon
,
1342 infragenericEpithetOfTaxon
,
1343 infraspecificEpithetOfTaxon
,
1344 taxonNames
, parentName
,
1347 inferredSynonyms
.add(inferredEpithet
);
1348 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1349 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1353 if (!taxonNames
.isEmpty()){
1354 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1355 ZoologicalName name
;
1356 if (!synNotInCDM
.isEmpty()){
1357 inferredSynonymsToBeRemoved
.clear();
1359 for (Synonym syn
:inferredSynonyms
){
1360 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1361 if (!synNotInCDM
.contains(name
.getNameCache())){
1362 inferredSynonymsToBeRemoved
.add(syn
);
1366 // Remove identified Synonyms from inferredSynonyms
1367 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1368 inferredSynonyms
.remove(synonym
);
1373 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1376 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1377 TaxonNameBase synName
;
1378 ZoologicalName inferredSynName
;
1380 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1381 inferredGenus
= createInferredGenus(taxon
,
1382 zooHashMap
, taxonName
, epithetOfTaxon
,
1383 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1385 inferredSynonyms
.add(inferredGenus
);
1386 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1387 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1392 if (doWithMisappliedNames
){
1394 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1395 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1396 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1398 inferredSynonyms
.add(inferredGenus
);
1399 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1400 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1405 if (!taxonNames
.isEmpty()){
1406 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1407 ZoologicalName name
;
1408 if (!synNotInCDM
.isEmpty()){
1409 inferredSynonymsToBeRemoved
.clear();
1411 for (Synonym syn
:inferredSynonyms
){
1412 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1413 if (!synNotInCDM
.contains(name
.getNameCache())){
1414 inferredSynonymsToBeRemoved
.add(syn
);
1418 // Remove identified Synonyms from inferredSynonyms
1419 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1420 inferredSynonyms
.remove(synonym
);
1425 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1427 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1428 ZoologicalName inferredSynName
;
1429 //for all synonyms of the parent...
1430 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1431 TaxonNameBase synName
;
1432 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1433 synName
= synParent
.getName();
1435 HibernateProxyHelper
.deproxy(synParent
);
1437 // Set the sourceReference
1438 sourceReference
= synParent
.getSec();
1440 // Determine the idInSource
1441 String idInSourceParent
= getIdInSource(synParent
);
1443 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1444 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1445 String synParentInfragenericName
= null;
1446 String synParentSpecificEpithet
= null;
1448 if (parentSynZooName
.isInfraGeneric()){
1449 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1451 if (parentSynZooName
.isSpecies()){
1452 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1455 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1456 synonymsGenus.put(synGenusName, idInSource);
1459 //for all synonyms of the taxon
1461 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1463 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1464 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1465 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1467 synParentInfragenericName
,
1468 synParentSpecificEpithet
, syn
, zooHashMap
);
1470 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1471 inferredSynonyms
.add(potentialCombination
);
1472 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1473 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1480 if (doWithMisappliedNames
){
1482 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1484 TaxonNameBase misappliedParentName
;
1486 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1487 misappliedParentName
= misappliedParent
.getName();
1489 HibernateProxyHelper
.deproxy(misappliedParent
);
1491 // Set the sourceReference
1492 sourceReference
= misappliedParent
.getSec();
1494 // Determine the idInSource
1495 String idInSourceParent
= getIdInSource(misappliedParent
);
1497 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1498 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1499 String synParentInfragenericName
= null;
1500 String synParentSpecificEpithet
= null;
1502 if (parentSynZooName
.isInfraGeneric()){
1503 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1505 if (parentSynZooName
.isSpecies()){
1506 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1510 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1511 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1512 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1513 potentialCombination
= createPotentialCombination(
1514 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1516 synParentInfragenericName
,
1517 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1520 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1521 inferredSynonyms
.add(potentialCombination
);
1522 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1523 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1528 if (!taxonNames
.isEmpty()){
1529 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1530 ZoologicalName name
;
1531 if (!synNotInCDM
.isEmpty()){
1532 inferredSynonymsToBeRemoved
.clear();
1533 for (Synonym syn
:inferredSynonyms
){
1535 name
= (ZoologicalName
) syn
.getName();
1536 }catch (ClassCastException e
){
1537 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1539 if (!synNotInCDM
.contains(name
.getNameCache())){
1540 inferredSynonymsToBeRemoved
.add(syn
);
1543 // Remove identified Synonyms from inferredSynonyms
1544 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1545 inferredSynonyms
.remove(synonym
);
1551 logger
.info("The synonymrelationship type is not defined.");
1552 return inferredSynonyms
;
1559 return inferredSynonyms
;
1562 private Synonym
createPotentialCombination(String idInSourceParent
,
1563 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1564 String synParentInfragenericName
, String synParentSpecificEpithet
,
1565 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1566 Synonym potentialCombination
;
1567 Reference sourceReference
;
1568 ZoologicalName inferredSynName
;
1569 HibernateProxyHelper
.deproxy(syn
);
1571 // Set sourceReference
1572 sourceReference
= syn
.getSec();
1573 if (sourceReference
== null){
1574 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1576 if (!parentSynZooName
.getTaxa().isEmpty()){
1577 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
1579 sourceReference
= taxon
.getSec();
1582 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1584 String synTaxonInfraSpecificName
= null;
1586 if (parentSynZooName
.isSpecies()){
1587 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1590 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1591 synonymsEpithet.add(epithetName);
1594 //create potential combinations...
1595 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1597 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1598 if (zooSynName
.isSpecies()){
1599 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1600 if (parentSynZooName
.isInfraGeneric()){
1601 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1604 if (zooSynName
.isInfraSpecific()){
1605 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1606 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1608 if (parentSynZooName
.isInfraGeneric()){
1609 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1613 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1615 // Set the sourceReference
1616 potentialCombination
.setSec(sourceReference
);
1619 // Determine the idInSource
1620 String idInSourceSyn
= getIdInSource(syn
);
1622 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1623 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1624 inferredSynName
.addSource(originalSource
);
1625 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1626 potentialCombination
.addSource(originalSource
);
1629 inferredSynName
.generateTitle();
1631 return potentialCombination
;
1634 private Synonym
createInferredGenus(Taxon taxon
,
1635 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1636 String epithetOfTaxon
, String genusOfTaxon
,
1637 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1640 Synonym inferredGenus
;
1641 TaxonNameBase synName
;
1642 ZoologicalName inferredSynName
;
1643 synName
=syn
.getName();
1644 HibernateProxyHelper
.deproxy(syn
);
1646 // Determine the idInSource
1647 String idInSourceSyn
= getIdInSource(syn
);
1648 String idInSourceTaxon
= getIdInSource(taxon
);
1649 // Determine the sourceReference
1650 Reference sourceReference
= syn
.getSec();
1652 //logger.warn(sourceReference.getTitleCache());
1654 synName
= syn
.getName();
1655 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1656 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1657 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1658 synonymsEpithet.add(synSpeciesEpithetName);
1661 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1662 //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...
1665 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1666 if (zooParentName
.isInfraGeneric()){
1667 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1670 if (taxonName
.isSpecies()){
1671 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1673 if (taxonName
.isInfraSpecific()){
1674 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1675 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1679 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1681 // Set the sourceReference
1682 inferredGenus
.setSec(sourceReference
);
1684 // Add the original source
1685 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1686 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1687 inferredGenus
.addSource(originalSource
);
1689 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1690 inferredSynName
.addSource(originalSource
);
1691 originalSource
= null;
1694 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
1695 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1696 inferredGenus
.addSource(originalSource
);
1698 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1699 inferredSynName
.addSource(originalSource
);
1700 originalSource
= null;
1703 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1705 inferredSynName
.generateTitle();
1708 return inferredGenus
;
1711 private Synonym
createInferredEpithets(Taxon taxon
,
1712 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1713 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1714 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1715 TaxonNameBase parentName
, TaxonBase syn
) {
1717 Synonym inferredEpithet
;
1718 TaxonNameBase synName
;
1719 ZoologicalName inferredSynName
;
1720 HibernateProxyHelper
.deproxy(syn
);
1722 // Determine the idInSource
1723 String idInSourceSyn
= getIdInSource(syn
);
1724 String idInSourceTaxon
= getIdInSource(taxon
);
1725 // Determine the sourceReference
1726 Reference sourceReference
= syn
.getSec();
1728 if (sourceReference
== null){
1729 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1731 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
1732 sourceReference
= taxon
.getSec();
1735 synName
= syn
.getName();
1736 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1737 String synGenusName
= zooSynName
.getGenusOrUninomial();
1738 String synInfraGenericEpithet
= null;
1739 String synSpecificEpithet
= null;
1741 if (zooSynName
.getInfraGenericEpithet() != null){
1742 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1745 if (zooSynName
.isInfraSpecific()){
1746 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1749 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1750 synonymsGenus.put(synGenusName, idInSource);
1753 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1755 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1756 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1757 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1759 inferredSynName
.setGenusOrUninomial(synGenusName
);
1761 if (parentName
.isInfraGeneric()){
1762 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1764 if (taxonName
.isSpecies()){
1765 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1766 }else if (taxonName
.isInfraSpecific()){
1767 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1768 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1771 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1773 // Set the sourceReference
1774 inferredEpithet
.setSec(sourceReference
);
1776 /* Add the original source
1777 if (idInSource != null) {
1778 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1781 Reference citation = getCitation(syn);
1782 if (citation != null) {
1783 originalSource.setCitation(citation);
1784 inferredEpithet.addSource(originalSource);
1787 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1789 IdentifiableSource originalSource
;
1790 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1792 inferredEpithet
.addSource(originalSource
);
1794 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1796 inferredSynName
.addSource(originalSource
);
1800 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1802 inferredSynName
.generateTitle();
1803 return inferredEpithet
;
1807 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1808 * Very likely only useful for createInferredSynonyms().
1813 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1814 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1815 if (taxonName
== null) {
1816 taxonName
= zooHashMap
.get(uuid
);
1822 * Returns the idInSource for a given Synonym.
1825 private String
getIdInSource(TaxonBase taxonBase
) {
1826 String idInSource
= null;
1827 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1828 if (sources
.size() == 1) {
1829 IdentifiableSource source
= sources
.iterator().next();
1830 if (source
!= null) {
1831 idInSource
= source
.getIdInSource();
1833 } else if (sources
.size() > 1) {
1836 for (IdentifiableSource source
: sources
) {
1837 idInSource
+= source
.getIdInSource();
1838 if (count
< sources
.size()) {
1843 } else if (sources
.size() == 0){
1844 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
1853 * Returns the citation for a given Synonym.
1856 private Reference
getCitation(Synonym syn
) {
1857 Reference citation
= null;
1858 Set
<IdentifiableSource
> sources
= syn
.getSources();
1859 if (sources
.size() == 1) {
1860 IdentifiableSource source
= sources
.iterator().next();
1861 if (source
!= null) {
1862 citation
= source
.getCitation();
1864 } else if (sources
.size() > 1) {
1865 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1871 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1872 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1874 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1875 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1876 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1878 return inferredSynonyms
;