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
;
1158 // queryString = queryString.toLowerCase();
1160 StringBuilder luceneQueryTemplate
= new StringBuilder();
1161 BooleanQuery finalQuery
= new BooleanQuery();
1162 BooleanQuery textQuery
= new BooleanQuery();
1163 Set
<String
> freetextFields
= new HashSet
<String
>();
1165 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), directorySelectClass
);
1166 QueryFactory queryBuilder
= new QueryFactory(luceneSearch
);
1168 // ---- search criteria
1170 // luceneQueryTemplate.append("+(");
1171 // luceneQueryTemplate.append("titleCache:(%1$s) ");
1172 freetextFields
.add("titleCache");
1173 textQuery
.add(queryBuilder
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1176 freetextFields
.add("name");
1179 if(languages
== null || languages
.size() == 0){
1180 // luceneQueryTemplate.append("name:(%1$s) ");
1181 nameQuery
= queryBuilder
.newTermQuery("name", queryString
);
1183 nameQuery
= new BooleanQuery();
1184 BooleanQuery languageSubQuery
= new BooleanQuery();
1185 // luceneQueryTemplate.append("(+name:(%1$s) ");
1186 for(Language lang
: languages
){
1187 // luceneQueryTemplate.append(" +language.uuid:" + lang.getUuid().toString());
1188 languageSubQuery
.add(queryBuilder
.newTermQuery("language.uuid", lang
.getUuid().toString()), Occur
.SHOULD
);
1190 ((BooleanQuery
) nameQuery
).add(queryBuilder
.newTermQuery("name", queryString
), Occur
.MUST
);
1191 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1192 // luceneQueryTemplate.append(")");
1194 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1197 // text field from TextData
1198 freetextFields
.add("text.ALL");
1199 // appendLocalizedFieldQuery("text", languages, luceneQueryTemplate).append(" ");
1200 textQuery
.add(queryBuilder
.newLocalizedTermQuery("text", queryString
, languages
), Occur
.SHOULD
);
1202 // --- TermBase fields - by representation ----
1203 // state field from CategoricalData
1204 freetextFields
.add("states.state.representation.ALL");
1205 // appendLocalizedFieldQuery("states.state.representation", languages, luceneQueryTemplate).append(" ");
1206 textQuery
.add(queryBuilder
.newLocalizedTermQuery("states.state.representation", queryString
, languages
), Occur
.SHOULD
);
1208 // state field from CategoricalData
1209 freetextFields
.add("states.modifyingText.ALL");
1210 // appendLocalizedFieldQuery("states.modifyingText", languages, luceneQueryTemplate).append(" ");
1211 textQuery
.add(queryBuilder
.newLocalizedTermQuery("states.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1212 // luceneQueryTemplate.append(") ");
1214 finalQuery
.add(textQuery
, Occur
.MUST
);
1215 // --- classification ----
1217 if(classification
!= null){
1218 // luceneQueryTemplate.append("+inDescription.taxon.taxonNodes.classification.id:").append(PaddedIntegerBridge.paddInteger(classification.getId())).append(" ");
1219 finalQuery
.add(queryBuilder
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
1222 // --- IdentifieableEntity fields - by uuid
1223 if(features
!= null && features
.size() > 0 ){
1224 finalQuery
.add(queryBuilder
.newEntityUuidQuery("feature.uuid", features
), Occur
.MUST
);
1225 // luceneQueryTemplate.append("+feature.uuid:(");
1226 // for(Feature feature : features){
1227 // luceneQueryTemplate.append(feature.getUuid()).append(" ");
1229 // luceneQueryTemplate.append(") ");
1232 // the description must be associated with a taxon
1233 // luceneQueryTemplate.append("+inDescription.taxon.id:[ " + PaddedIntegerBridge.paddInteger(0) + " TO " + PaddedIntegerBridge.paddInteger(Integer.MAX_VALUE) + "] ");
1234 //luceneQueryTemplate.append("-inDescription.taxon.id:" + PaddedIntegerBridge.NULL_STRING);
1235 finalQuery
.add(queryBuilder
.newIdNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
1237 // String luceneQueryStr = String.format(luceneQueryTemplate.toString(), queryString);
1240 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", false)};
1242 // ---- execute criteria
1245 // Query luceneQuery = luceneSearch.parse(luceneQueryStr);
1246 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(finalQuery
, clazz
, pageSize
, pageNumber
, sortFields
);
1248 String
[] highlightFields
= null;
1249 if(highlightFragments
){
1250 highlightFields
= freetextFields
.toArray(new String
[freetextFields
.size()]);
1253 // initialize taxa, thighlight matches ....
1254 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, finalQuery
);
1255 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1256 topDocsResultSet
, highlightFields
, dao
, "inDescription.taxon.id", propertyPaths
);
1258 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
1263 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1264 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1265 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1267 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1268 * or {@link MultilanguageTextFieldBridge }
1269 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1270 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1271 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1273 * TODO move to utiliy class !!!!!!!!
1275 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1277 if(stringBuilder
== null){
1278 stringBuilder
= new StringBuilder();
1280 if(languages
== null || languages
.size() == 0){
1281 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
1283 for(Language lang
: languages
){
1284 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
1287 return stringBuilder
;
1290 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1291 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1292 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1294 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1297 UUID uuid
= taxon
.getName().getUuid();
1298 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1299 String epithetOfTaxon
= null;
1300 String infragenericEpithetOfTaxon
= null;
1301 String infraspecificEpithetOfTaxon
= null;
1302 if (taxonName
.isSpecies()){
1303 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1304 } else if (taxonName
.isInfraGeneric()){
1305 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1306 } else if (taxonName
.isInfraSpecific()){
1307 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1309 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1310 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1311 List
<String
> taxonNames
= new ArrayList
<String
>();
1313 for (TaxonNode node
: nodes
){
1314 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1315 // List<String> synonymsEpithet = new ArrayList<String>();
1317 if (node
.getClassification().equals(classification
)){
1318 if (!node
.isTopmostNode()){
1319 TaxonNode parent
= (TaxonNode
)node
.getParent();
1320 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1321 TaxonNameBase parentName
= parent
.getTaxon().getName();
1322 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1323 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1324 Rank rankOfTaxon
= taxonName
.getRank();
1327 //create inferred synonyms for species, subspecies
1328 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1330 Synonym inferredEpithet
= null;
1331 Synonym inferredGenus
= null;
1332 Synonym potentialCombination
= null;
1334 List
<String
> propertyPaths
= new ArrayList
<String
>();
1335 propertyPaths
.add("synonym");
1336 propertyPaths
.add("synonym.name");
1337 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1338 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1340 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1341 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1343 List
<TaxonRelationship
> taxonRelListParent
= null;
1344 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1345 if (doWithMisappliedNames
){
1346 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1347 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1351 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1352 Set
<String
> genusNames
= new HashSet
<String
>();
1354 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1355 Synonym syn
= synonymRelationOfParent
.getSynonym();
1357 inferredEpithet
= createInferredEpithets(taxon
,
1358 zooHashMap
, taxonName
, epithetOfTaxon
,
1359 infragenericEpithetOfTaxon
,
1360 infraspecificEpithetOfTaxon
,
1361 taxonNames
, parentName
,
1365 inferredSynonyms
.add(inferredEpithet
);
1366 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1367 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1370 if (doWithMisappliedNames
){
1372 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1373 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1375 inferredEpithet
= createInferredEpithets(taxon
,
1376 zooHashMap
, taxonName
, epithetOfTaxon
,
1377 infragenericEpithetOfTaxon
,
1378 infraspecificEpithetOfTaxon
,
1379 taxonNames
, parentName
,
1382 inferredSynonyms
.add(inferredEpithet
);
1383 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1384 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1388 if (!taxonNames
.isEmpty()){
1389 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1390 ZoologicalName name
;
1391 if (!synNotInCDM
.isEmpty()){
1392 inferredSynonymsToBeRemoved
.clear();
1394 for (Synonym syn
:inferredSynonyms
){
1395 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1396 if (!synNotInCDM
.contains(name
.getNameCache())){
1397 inferredSynonymsToBeRemoved
.add(syn
);
1401 // Remove identified Synonyms from inferredSynonyms
1402 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1403 inferredSynonyms
.remove(synonym
);
1408 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1411 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1412 TaxonNameBase synName
;
1413 ZoologicalName inferredSynName
;
1415 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1416 inferredGenus
= createInferredGenus(taxon
,
1417 zooHashMap
, taxonName
, epithetOfTaxon
,
1418 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1420 inferredSynonyms
.add(inferredGenus
);
1421 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1422 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1427 if (doWithMisappliedNames
){
1429 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1430 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1431 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1433 inferredSynonyms
.add(inferredGenus
);
1434 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1435 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1440 if (!taxonNames
.isEmpty()){
1441 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1442 ZoologicalName name
;
1443 if (!synNotInCDM
.isEmpty()){
1444 inferredSynonymsToBeRemoved
.clear();
1446 for (Synonym syn
:inferredSynonyms
){
1447 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1448 if (!synNotInCDM
.contains(name
.getNameCache())){
1449 inferredSynonymsToBeRemoved
.add(syn
);
1453 // Remove identified Synonyms from inferredSynonyms
1454 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1455 inferredSynonyms
.remove(synonym
);
1460 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1462 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1463 ZoologicalName inferredSynName
;
1464 //for all synonyms of the parent...
1465 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1466 TaxonNameBase synName
;
1467 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1468 synName
= synParent
.getName();
1470 HibernateProxyHelper
.deproxy(synParent
);
1472 // Set the sourceReference
1473 sourceReference
= synParent
.getSec();
1475 // Determine the idInSource
1476 String idInSourceParent
= getIdInSource(synParent
);
1478 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1479 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1480 String synParentInfragenericName
= null;
1481 String synParentSpecificEpithet
= null;
1483 if (parentSynZooName
.isInfraGeneric()){
1484 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1486 if (parentSynZooName
.isSpecies()){
1487 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1490 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1491 synonymsGenus.put(synGenusName, idInSource);
1494 //for all synonyms of the taxon
1496 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1498 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1499 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1500 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1502 synParentInfragenericName
,
1503 synParentSpecificEpithet
, syn
, zooHashMap
);
1505 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1506 inferredSynonyms
.add(potentialCombination
);
1507 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1508 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1515 if (doWithMisappliedNames
){
1517 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1519 TaxonNameBase misappliedParentName
;
1521 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1522 misappliedParentName
= misappliedParent
.getName();
1524 HibernateProxyHelper
.deproxy(misappliedParent
);
1526 // Set the sourceReference
1527 sourceReference
= misappliedParent
.getSec();
1529 // Determine the idInSource
1530 String idInSourceParent
= getIdInSource(misappliedParent
);
1532 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1533 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1534 String synParentInfragenericName
= null;
1535 String synParentSpecificEpithet
= null;
1537 if (parentSynZooName
.isInfraGeneric()){
1538 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1540 if (parentSynZooName
.isSpecies()){
1541 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1545 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1546 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1547 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1548 potentialCombination
= createPotentialCombination(
1549 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1551 synParentInfragenericName
,
1552 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1555 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1556 inferredSynonyms
.add(potentialCombination
);
1557 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1558 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1563 if (!taxonNames
.isEmpty()){
1564 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1565 ZoologicalName name
;
1566 if (!synNotInCDM
.isEmpty()){
1567 inferredSynonymsToBeRemoved
.clear();
1568 for (Synonym syn
:inferredSynonyms
){
1570 name
= (ZoologicalName
) syn
.getName();
1571 }catch (ClassCastException e
){
1572 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1574 if (!synNotInCDM
.contains(name
.getNameCache())){
1575 inferredSynonymsToBeRemoved
.add(syn
);
1578 // Remove identified Synonyms from inferredSynonyms
1579 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1580 inferredSynonyms
.remove(synonym
);
1586 logger
.info("The synonymrelationship type is not defined.");
1587 return inferredSynonyms
;
1594 return inferredSynonyms
;
1597 private Synonym
createPotentialCombination(String idInSourceParent
,
1598 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1599 String synParentInfragenericName
, String synParentSpecificEpithet
,
1600 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1601 Synonym potentialCombination
;
1602 Reference sourceReference
;
1603 ZoologicalName inferredSynName
;
1604 HibernateProxyHelper
.deproxy(syn
);
1606 // Set sourceReference
1607 sourceReference
= syn
.getSec();
1608 if (sourceReference
== null){
1609 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1611 if (!parentSynZooName
.getTaxa().isEmpty()){
1612 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
1614 sourceReference
= taxon
.getSec();
1617 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1619 String synTaxonInfraSpecificName
= null;
1621 if (parentSynZooName
.isSpecies()){
1622 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1625 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1626 synonymsEpithet.add(epithetName);
1629 //create potential combinations...
1630 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1632 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1633 if (zooSynName
.isSpecies()){
1634 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1635 if (parentSynZooName
.isInfraGeneric()){
1636 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1639 if (zooSynName
.isInfraSpecific()){
1640 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1641 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1643 if (parentSynZooName
.isInfraGeneric()){
1644 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1648 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1650 // Set the sourceReference
1651 potentialCombination
.setSec(sourceReference
);
1654 // Determine the idInSource
1655 String idInSourceSyn
= getIdInSource(syn
);
1657 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1658 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1659 inferredSynName
.addSource(originalSource
);
1660 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1661 potentialCombination
.addSource(originalSource
);
1664 inferredSynName
.generateTitle();
1666 return potentialCombination
;
1669 private Synonym
createInferredGenus(Taxon taxon
,
1670 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1671 String epithetOfTaxon
, String genusOfTaxon
,
1672 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1675 Synonym inferredGenus
;
1676 TaxonNameBase synName
;
1677 ZoologicalName inferredSynName
;
1678 synName
=syn
.getName();
1679 HibernateProxyHelper
.deproxy(syn
);
1681 // Determine the idInSource
1682 String idInSourceSyn
= getIdInSource(syn
);
1683 String idInSourceTaxon
= getIdInSource(taxon
);
1684 // Determine the sourceReference
1685 Reference sourceReference
= syn
.getSec();
1687 //logger.warn(sourceReference.getTitleCache());
1689 synName
= syn
.getName();
1690 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1691 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1692 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1693 synonymsEpithet.add(synSpeciesEpithetName);
1696 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1697 //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...
1700 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1701 if (zooParentName
.isInfraGeneric()){
1702 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1705 if (taxonName
.isSpecies()){
1706 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1708 if (taxonName
.isInfraSpecific()){
1709 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1710 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1714 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1716 // Set the sourceReference
1717 inferredGenus
.setSec(sourceReference
);
1719 // Add the original source
1720 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1721 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1722 inferredGenus
.addSource(originalSource
);
1724 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1725 inferredSynName
.addSource(originalSource
);
1726 originalSource
= null;
1729 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
1730 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1731 inferredGenus
.addSource(originalSource
);
1733 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1734 inferredSynName
.addSource(originalSource
);
1735 originalSource
= null;
1738 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1740 inferredSynName
.generateTitle();
1743 return inferredGenus
;
1746 private Synonym
createInferredEpithets(Taxon taxon
,
1747 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1748 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1749 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1750 TaxonNameBase parentName
, TaxonBase syn
) {
1752 Synonym inferredEpithet
;
1753 TaxonNameBase synName
;
1754 ZoologicalName inferredSynName
;
1755 HibernateProxyHelper
.deproxy(syn
);
1757 // Determine the idInSource
1758 String idInSourceSyn
= getIdInSource(syn
);
1759 String idInSourceTaxon
= getIdInSource(taxon
);
1760 // Determine the sourceReference
1761 Reference sourceReference
= syn
.getSec();
1763 if (sourceReference
== null){
1764 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1766 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
1767 sourceReference
= taxon
.getSec();
1770 synName
= syn
.getName();
1771 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1772 String synGenusName
= zooSynName
.getGenusOrUninomial();
1773 String synInfraGenericEpithet
= null;
1774 String synSpecificEpithet
= null;
1776 if (zooSynName
.getInfraGenericEpithet() != null){
1777 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1780 if (zooSynName
.isInfraSpecific()){
1781 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1784 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1785 synonymsGenus.put(synGenusName, idInSource);
1788 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1790 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1791 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1792 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1794 inferredSynName
.setGenusOrUninomial(synGenusName
);
1796 if (parentName
.isInfraGeneric()){
1797 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1799 if (taxonName
.isSpecies()){
1800 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1801 }else if (taxonName
.isInfraSpecific()){
1802 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1803 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1806 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1808 // Set the sourceReference
1809 inferredEpithet
.setSec(sourceReference
);
1811 /* Add the original source
1812 if (idInSource != null) {
1813 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1816 Reference citation = getCitation(syn);
1817 if (citation != null) {
1818 originalSource.setCitation(citation);
1819 inferredEpithet.addSource(originalSource);
1822 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1824 IdentifiableSource originalSource
;
1825 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1827 inferredEpithet
.addSource(originalSource
);
1829 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1831 inferredSynName
.addSource(originalSource
);
1835 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1837 inferredSynName
.generateTitle();
1838 return inferredEpithet
;
1842 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1843 * Very likely only useful for createInferredSynonyms().
1848 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1849 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1850 if (taxonName
== null) {
1851 taxonName
= zooHashMap
.get(uuid
);
1857 * Returns the idInSource for a given Synonym.
1860 private String
getIdInSource(TaxonBase taxonBase
) {
1861 String idInSource
= null;
1862 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1863 if (sources
.size() == 1) {
1864 IdentifiableSource source
= sources
.iterator().next();
1865 if (source
!= null) {
1866 idInSource
= source
.getIdInSource();
1868 } else if (sources
.size() > 1) {
1871 for (IdentifiableSource source
: sources
) {
1872 idInSource
+= source
.getIdInSource();
1873 if (count
< sources
.size()) {
1878 } else if (sources
.size() == 0){
1879 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
1888 * Returns the citation for a given Synonym.
1891 private Reference
getCitation(Synonym syn
) {
1892 Reference citation
= null;
1893 Set
<IdentifiableSource
> sources
= syn
.getSources();
1894 if (sources
.size() == 1) {
1895 IdentifiableSource source
= sources
.iterator().next();
1896 if (source
!= null) {
1897 citation
= source
.getCitation();
1899 } else if (sources
.size() > 1) {
1900 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1906 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1907 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1909 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1910 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1911 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1913 return inferredSynonyms
;