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
.description
.TextData
;
67 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
68 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
69 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
70 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
71 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
72 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
73 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
74 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
75 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
76 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
77 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
78 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
79 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
80 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
81 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
82 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
83 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
84 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
85 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
86 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
87 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
88 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
89 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
90 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
91 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
92 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
93 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
97 * @author a.kohlbecker
102 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
103 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
104 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
106 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
108 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
110 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
114 private ITaxonNameDao nameDao
;
117 private INameService nameService
;
120 private ICdmGenericDao genericDao
;
123 private IDescriptionService descriptionService
;
126 private IOrderedTermVocabularyDao orderedVocabularyDao
;
131 public TaxonServiceImpl(){
132 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
136 * FIXME Candidate for harmonization
137 * rename searchByName ?
139 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
140 return dao
.getTaxaByName(name
, sec
);
144 * FIXME Candidate for harmonization
145 * list(Synonym.class, ...)
147 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
149 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
150 return dao
.getAllSynonyms(limit
, start
);
154 * FIXME Candidate for harmonization
155 * list(Taxon.class, ...)
157 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
159 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
160 return dao
.getAllTaxa(limit
, start
);
164 * FIXME Candidate for harmonization
165 * merge with getRootTaxa(Reference sec, ..., ...)
167 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
169 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
170 if (cdmFetch
== null){
171 cdmFetch
= CdmFetch
.NO_FETCH();
173 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
178 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
180 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
181 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
185 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
187 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
188 return dao
.getAllRelationships(limit
, start
);
192 * FIXME Candidate for harmonization
193 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
196 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
198 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
199 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
200 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
201 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
202 return taxonRelTypeVocabulary
;
209 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
211 @Transactional(readOnly
= false)
212 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
214 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
215 synonymName
.removeTaxonBase(synonym
);
216 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
217 taxonName
.removeTaxonBase(acceptedTaxon
);
219 synonym
.setName(taxonName
);
220 acceptedTaxon
.setName(synonymName
);
222 // the accepted taxon needs a new uuid because the concept has changed
223 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
224 //acceptedTaxon.setUuid(UUID.randomUUID());
229 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
231 //TODO correct delete handling still needs to be implemented / checked
233 @Transactional(readOnly
= false)
234 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
236 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
237 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
238 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
240 //check synonym is not homotypic
241 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
242 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
243 throw new HomotypicalGroupChangeException(message
);
246 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
248 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
249 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
251 for (Synonym heteroSynonym
: heteroSynonyms
){
252 if (synonym
.equals(heteroSynonym
)){
253 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
255 //move synonyms in same homotypic group to new accepted taxon
256 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
260 //synonym.getName().removeTaxonBase(synonym);
261 //TODO correct delete handling still needs to be implemented / checked
263 // deleteSynonym(synonym, taxon, false);
266 this.delete(synonym
);
268 } catch (Exception e
) {
269 logger
.info("Can't delete old synonym from database");
273 return newAcceptedTaxon
;
277 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
279 // Get name from synonym
280 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
282 // remove synonym from taxon
283 toTaxon
.removeSynonym(synonym
);
285 // Create a taxon with synonym name
286 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
288 // Add taxon relation
289 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
291 // since we are swapping names, we have to detach the name from the synonym completely.
292 // Otherwise the synonym will still be in the list of typified names.
293 synonym
.getName().removeTaxonBase(synonym
);
300 * @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)
302 @Transactional(readOnly
= false)
304 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
305 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
307 TaxonNameBase synonymName
= synonym
.getName();
308 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
312 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
313 newHomotypicalGroup
.addTypifiedName(synonymName
);
315 //remove existing basionym relationships
316 synonymName
.removeBasionyms();
318 //add basionym relationship
319 if (setBasionymRelationIfApplicable
){
320 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
321 for (TaxonNameBase basionym
: basionyms
){
322 synonymName
.addBasionym(basionym
);
326 //set synonym relationship correctly
327 // SynonymRelationship relToTaxon = null;
328 boolean relToTargetTaxonExists
= false;
329 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
330 for (SynonymRelationship rel
: existingRelations
){
331 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
332 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
333 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
334 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
335 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
336 rel
.setType(newRelationType
);
337 //TODO handle citation and microCitation
340 relToTargetTaxonExists
= true;
342 if (removeFromOtherTaxa
){
343 acceptedTaxon
.removeSynonym(synonym
, false);
349 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
350 Taxon acceptedTaxon
= targetTaxon
;
351 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
352 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
353 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
354 //TODO handle citation and microCitation
355 Reference citation
= null;
356 String microCitation
= null;
357 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
364 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
367 @Transactional(readOnly
= false)
368 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
370 clazz
= TaxonBase
.class;
372 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
376 protected void setDao(ITaxonDao dao
) {
381 * @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)
383 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
384 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
386 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
387 if(numberOfResults
> 0) { // no point checking again
388 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
391 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
395 * @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)
397 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
398 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
400 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
401 if(numberOfResults
> 0) { // no point checking again
402 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
409 * @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)
411 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
412 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
414 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
415 if(numberOfResults
> 0) { // no point checking again
416 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
422 * @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)
424 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
425 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
427 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
428 if(numberOfResults
> 0) { // no point checking again
429 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
431 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
435 * @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)
437 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
438 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
440 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
441 if(numberOfResults
> 0) { // no point checking again
442 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
448 * @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)
450 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
451 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
453 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
454 if(numberOfResults
> 0) { // no point checking again
455 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
457 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
461 * @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)
463 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
464 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
466 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
467 if(numberOfResults
> 0) { // no point checking again
468 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
471 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
475 * @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)
477 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
478 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
480 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
481 if(numberOfResults
> 0) { // no point checking again
482 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
485 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
489 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
491 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
492 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
493 return t
.getHomotypicSynonymsByHomotypicGroup();
497 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
499 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
500 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
501 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
502 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
503 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
504 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
506 return heterotypicSynonymyGroups
;
509 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
511 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
512 // Class<? extends TaxonBase> clazz = null;
513 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
514 // clazz = TaxonBase.class;
515 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
516 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
517 // } else if(configurator.isDoTaxa()) {
518 // clazz = Taxon.class;
519 // //propertyPath = configurator.getTaxonPropertyPath();
520 // } else if (configurator.isDoSynonyms()) {
521 // clazz = Synonym.class;
522 // //propertyPath = configurator.getSynonymPropertyPath();
526 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
531 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
533 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
535 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
536 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
537 List
<TaxonBase
> taxa
= null;
540 long numberTaxaResults
= 0L;
543 List
<String
> propertyPath
= new ArrayList
<String
>();
544 if(configurator
.getTaxonPropertyPath() != null){
545 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
549 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
550 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
552 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
553 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
554 configurator
.getNamedAreas());
557 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
558 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
559 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
560 configurator
.getMatchMode(), configurator
.getNamedAreas(),
561 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
565 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
568 results
.addAll(taxa
);
571 numberOfResults
+= numberTaxaResults
;
573 // Names without taxa
574 if (configurator
.isDoNamesWithoutTaxa()) {
575 int numberNameResults
= 0;
577 List
<?
extends TaxonNameBase
<?
,?
>> names
=
578 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
579 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
580 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
581 if (names
.size() > 0) {
582 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
583 if (taxonName
.getTaxonBases().size() == 0) {
584 results
.add(taxonName
);
588 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
589 numberOfResults
+= numberNameResults
;
593 // Taxa from common names
595 if (configurator
.isDoTaxaByCommonNames()) {
596 taxa
= new ArrayList
<TaxonBase
>();
597 numberTaxaResults
= 0;
598 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
599 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
601 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
602 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
603 for( Object
[] entry
: commonNameResults
) {
604 taxa
.add((TaxonBase
) entry
[0]);
608 results
.addAll(taxa
);
610 numberOfResults
+= numberTaxaResults
;
614 return new DefaultPagerImpl
<IdentifiableEntity
>
615 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
618 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
619 return dao
.getUuidAndTitleCache();
623 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
625 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
626 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
627 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
628 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
629 for (TaxonDescription taxDesc
: descriptions
){
630 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
631 for (DescriptionElementBase descElem
: elements
){
632 for(Media media
: descElem
.getMedia()){
634 //find the best matching representation
635 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
644 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
646 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, boolean limitToGalleries
, List
<String
> propertyPath
){
648 Pager
<TaxonDescription
> p
=
649 descriptionService
.getTaxonDescriptions(taxon
, null, null, null, null, propertyPath
);
651 // pars the media and quality parameters
654 // collect all media of the given taxon
655 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
656 List
<Media
> taxonGalleryMedia
= new ArrayList
<Media
>();
657 for(TaxonDescription desc
: p
.getRecords()){
659 if(desc
.isImageGallery()){
660 for(DescriptionElementBase element
: desc
.getElements()){
661 for(Media media
: element
.getMedia()){
662 taxonGalleryMedia
.add(media
);
665 } else if(!limitToGalleries
){
666 for(DescriptionElementBase element
: desc
.getElements()){
667 for(Media media
: element
.getMedia()){
668 taxonMedia
.add(media
);
675 taxonGalleryMedia
.addAll(taxonMedia
);
676 return taxonGalleryMedia
;
680 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
682 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
683 return this.dao
.findById(listOfIDs
);
687 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
689 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
690 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
694 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
696 public int countAllRelationships() {
697 return this.dao
.countAllRelationships();
704 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
706 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
707 return this.dao
.findIdenticalTaxonNames(propertyPath
);
712 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
715 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
717 config
= new TaxonDeletionConfigurator();
721 if (! config
.isDeleteTaxonNodes()){
722 if (taxon
.getTaxonNodes().size() > 0){
723 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
724 throw new ReferencedObjectUndeletableException(message
);
729 // SynonymRelationShip
730 if (config
.isDeleteSynonymRelations()){
731 boolean removeSynonymNameFromHomotypicalGroup
= false;
732 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
733 Synonym synonym
= synRel
.getSynonym();
734 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
735 if (config
.isDeleteSynonymsIfPossible()){
737 boolean newHomotypicGroupIfNeeded
= true;
738 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
740 deleteSynonymRelationships(synonym
, taxon
);
746 if (! config
.isDeleteTaxonRelationships()){
747 if (taxon
.getTaxonRelations().size() > 0){
748 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.";
749 throw new ReferencedObjectUndeletableException(message
);
755 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
757 for (TaxonDescription desc
: descriptions
){
758 if (config
.isDeleteDescriptions()){
759 //TODO use description delete configurator ?
760 //FIXME check if description is ALWAYS deletable
761 descriptionService
.delete(desc
);
763 if (desc
.getDescribedSpecimenOrObservations().size()>0){
764 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
765 " which also describes specimens or abservations";
766 throw new ReferencedObjectUndeletableException(message
);
772 //check references with only reverse mapping
773 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
774 for (CdmBase referencingObject
: referencingObjects
){
775 //IIdentificationKeys (Media, Polytomous, MultiAccess)
776 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
777 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
778 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
779 throw new ReferencedObjectUndeletableException(message
);
784 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
785 String message
= "Taxon can't be deleted as it is used in polytomous key node";
786 throw new ReferencedObjectUndeletableException(message
);
790 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
791 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
792 throw new ReferencedObjectUndeletableException(message
);
798 if (config
.isDeleteNameIfPossible()){
800 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
801 } catch (ReferencedObjectUndeletableException e
) {
803 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
810 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
812 @Transactional(readOnly
= false)
814 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
815 if (synonym
== null){
818 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
820 //remove synonymRelationship
821 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
825 taxonSet
.addAll(synonym
.getAcceptedTaxa());
827 for (Taxon relatedTaxon
: taxonSet
){
828 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
829 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
831 this.saveOrUpdate(synonym
);
833 //TODO remove name from homotypical group?
835 //remove synonym (if necessary)
836 if (synonym
.getSynonymRelations().isEmpty()){
837 TaxonNameBase
<?
,?
> name
= synonym
.getName();
838 synonym
.setName(null);
841 //remove name if possible (and required)
842 if (name
!= null && removeNameIfPossible
){
844 nameService
.delete(name
, new NameDeletionConfigurator());
845 }catch (DataChangeNoRollbackException ex
){
846 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
854 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
856 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
858 return this.dao
.findIdenticalNamesNew(propertyPath
);
862 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
864 public String
getPhylumName(TaxonNameBase name
){
865 return this.dao
.getPhylumName(name
);
869 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
871 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
872 return dao
.deleteSynonymRelationships(syn
, taxon
);
876 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
878 public long deleteSynonymRelationships(Synonym syn
) {
879 return dao
.deleteSynonymRelationships(syn
, null);
884 * @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)
886 public List
<SynonymRelationship
> listSynonymRelationships(
887 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
888 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
889 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
891 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
892 if(numberOfResults
> 0) { // no point checking again
893 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
899 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
902 public Taxon
findBestMatchingTaxon(String taxonName
) {
903 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
904 config
.setTaxonNameTitle(taxonName
);
905 return findBestMatchingTaxon(config
);
911 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
913 Taxon bestCandidate
= null;
915 // 1. search for acceptet taxa
916 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
917 boolean bestCandidateMatchesSecUuid
= false;
918 boolean bestCandidateIsInClassification
= false;
919 int countEqualCandidates
= 0;
920 for(TaxonBase taxonBaseCandidate
: taxonList
){
921 if(taxonBaseCandidate
instanceof Taxon
){
922 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
923 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
924 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
926 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
927 bestCandidate
= newCanditate
;
928 countEqualCandidates
= 1;
929 bestCandidateMatchesSecUuid
= true;
933 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
934 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
936 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
937 bestCandidate
= newCanditate
;
938 countEqualCandidates
= 1;
939 bestCandidateIsInClassification
= true;
942 if (bestCandidate
== null){
943 bestCandidate
= newCanditate
;
944 countEqualCandidates
= 1;
948 }else{ //not Taxon.class
951 countEqualCandidates
++;
954 if (bestCandidate
!= null){
955 if(countEqualCandidates
> 1){
956 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
957 return bestCandidate
;
959 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
960 return bestCandidate
;
965 // 2. search for synonyms
966 if (config
.isIncludeSynonyms()){
967 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
968 for(TaxonBase taxonBase
: synonymList
){
969 if(taxonBase
instanceof Synonym
){
970 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
971 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
972 if(!acceptetdCandidates
.isEmpty()){
973 bestCandidate
= acceptetdCandidates
.iterator().next();
974 if(acceptetdCandidates
.size() == 1){
975 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
976 return bestCandidate
;
978 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
979 return bestCandidate
;
981 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
987 } catch (Exception e
){
991 return bestCandidate
;
994 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
995 UUID configClassificationUuid
= config
.getClassificationUuid();
996 if (configClassificationUuid
== null){
999 for (TaxonNode node
: taxon
.getTaxonNodes()){
1000 UUID classUuid
= node
.getClassification().getUuid();
1001 if (configClassificationUuid
.equals(classUuid
)){
1008 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1009 UUID configSecUuid
= config
.getSecUuid();
1010 if (configSecUuid
== null){
1013 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1014 return configSecUuid
.equals(taxonSecUuid
);
1018 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1021 public Synonym
findBestMatchingSynonym(String taxonName
) {
1022 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1023 if(! synonymList
.isEmpty()){
1024 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1025 if(synonymList
.size() == 1){
1026 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1029 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1038 * @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)
1041 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1042 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1044 Synonym synonym
= oldSynonymRelation
.getSynonym();
1045 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1046 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1047 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1048 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1049 //set default relationship type
1050 if (newSynonymRelationshipType
== null){
1051 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1053 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1055 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1056 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1057 boolean isSingleInGroup
= !(hgSize
> 1);
1059 if (! isSingleInGroup
){
1060 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1061 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1062 if (isHomotypicToAccepted
){
1063 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.";
1064 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1065 message
= String
.format(message
, homotypicRelatives
);
1066 throw new HomotypicalGroupChangeException(message
);
1068 if (! moveHomotypicGroup
){
1069 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.";
1070 throw new HomotypicalGroupChangeException(message
);
1073 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1075 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1077 SynonymRelationship result
= null;
1078 //move all synonyms to new taxon
1079 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1080 for (Synonym syn
: homotypicSynonyms
){
1081 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1082 for (SynonymRelationship synRelation
: synRelations
){
1083 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1084 Reference
<?
> newReference
= reference
;
1085 if (newReference
== null && keepReference
){
1086 newReference
= synRelation
.getCitation();
1088 String newRefDetail
= referenceDetail
;
1089 if (newRefDetail
== null && keepReference
){
1090 newRefDetail
= synRelation
.getCitationMicroReference();
1092 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1093 fromTaxon
.removeSynonymRelation(synRelation
, false);
1095 //change homotypic group of synonym if relType is 'homotypic'
1096 // if (newRelTypeIsHomotypic){
1097 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1100 if (synRelation
.equals(oldSynonymRelation
)){
1101 result
= newSynRelation
;
1107 saveOrUpdate(newTaxon
);
1108 //Assert that there is a result
1109 if (result
== null){
1110 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1111 throw new IllegalStateException(message
);
1117 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1120 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1121 return dao
.getUuidAndTitleCacheTaxon();
1125 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1128 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1129 return dao
.getUuidAndTitleCacheSynonym();
1133 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
1136 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1137 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1138 Classification classification
, List
<Language
> languages
,
1139 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1142 // abstract base classes cannot be used as directorySelectClass but any subclass will do!
1143 Class
<?
extends TaxonBase
> directorySelectClass
= Taxon
.class;
1145 if(clazz
.equals(TaxonBase
.class)){
1148 directorySelectClass
= clazz
;
1152 BooleanQuery finalQuery
= new BooleanQuery();
1153 BooleanQuery textQuery
= new BooleanQuery();
1155 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), directorySelectClass
);
1156 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1158 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", false)};
1160 // ---- search criteria
1161 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1162 textQuery
.add(queryFactory
.newDefinedTermBaseQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1164 finalQuery
.add(textQuery
, Occur
.MUST
);
1166 if(classification
!= null){
1167 finalQuery
.add(queryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1170 String
[] highlightFields
= null;
1171 if(highlightFragments
){
1172 highlightFields
= queryFactory
.getTextFieldNamesAsArray();
1175 // --- execute search
1176 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(finalQuery
, clazz
, pageSize
, pageNumber
, sortFields
);
1178 // --- initialize taxa, thighlight matches ....
1179 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, finalQuery
);
1180 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1181 topDocsResultSet
, highlightFields
, dao
, "taxon.id", propertyPaths
);
1183 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
1188 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findByDescriptionElementFullText(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.List, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
1191 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1192 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1193 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1194 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1197 // abstract base classes cannot be used as directorySelectClass but any subclass will do!
1198 Class
<?
extends DescriptionElementBase
> directorySelectClass
= TextData
.class;
1200 if(clazz
.equals(TaxonBase
.class)){
1203 directorySelectClass
= clazz
;
1207 BooleanQuery finalQuery
= new BooleanQuery();
1208 BooleanQuery textQuery
= new BooleanQuery();
1210 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), directorySelectClass
);
1211 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1213 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", false)};
1215 // ---- search criteria
1216 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1220 if(languages
== null || languages
.size() == 0){
1221 nameQuery
= queryFactory
.newTermQuery("name", queryString
);
1223 nameQuery
= new BooleanQuery();
1224 BooleanQuery languageSubQuery
= new BooleanQuery();
1225 for(Language lang
: languages
){
1226 languageSubQuery
.add(queryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString()), Occur
.SHOULD
);
1228 ((BooleanQuery
) nameQuery
).add(queryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
1229 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1231 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1234 // text field from TextData
1235 textQuery
.add(queryFactory
.newLocalizedTermQuery("text", queryString
, languages
), Occur
.SHOULD
);
1237 // --- TermBase fields - by representation ----
1238 // state field from CategoricalData
1239 textQuery
.add(queryFactory
.newLocalizedTermQuery("states.state.representation", queryString
, languages
), Occur
.SHOULD
);
1241 // state field from CategoricalData
1242 textQuery
.add(queryFactory
.newLocalizedTermQuery("states.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1244 finalQuery
.add(textQuery
, Occur
.MUST
);
1245 // --- classification ----
1247 if(classification
!= null){
1248 finalQuery
.add(queryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
1251 // --- IdentifieableEntity fields - by uuid
1252 if(features
!= null && features
.size() > 0 ){
1253 finalQuery
.add(queryFactory
.newEntityUuidQuery("feature.uuid", features
), Occur
.MUST
);
1256 // the description must be associated with a taxon
1257 finalQuery
.add(queryFactory
.newIdNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
1260 String
[] highlightFields
= null;
1261 if(highlightFragments
){
1262 highlightFields
= queryFactory
.getTextFieldNamesAsArray();
1265 // --- execute search
1266 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(finalQuery
, clazz
, pageSize
, pageNumber
, sortFields
);
1268 // --- initialize taxa, thighlight matches ....
1269 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, finalQuery
);
1270 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1271 topDocsResultSet
, highlightFields
, dao
, "inDescription.taxon.id", propertyPaths
);
1273 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
1278 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1279 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1280 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1282 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1283 * or {@link MultilanguageTextFieldBridge }
1284 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1285 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1286 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1288 * TODO move to utiliy class !!!!!!!!
1290 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1292 if(stringBuilder
== null){
1293 stringBuilder
= new StringBuilder();
1295 if(languages
== null || languages
.size() == 0){
1296 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
1298 for(Language lang
: languages
){
1299 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
1302 return stringBuilder
;
1305 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1306 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1307 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1309 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1312 UUID uuid
= taxon
.getName().getUuid();
1313 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1314 String epithetOfTaxon
= null;
1315 String infragenericEpithetOfTaxon
= null;
1316 String infraspecificEpithetOfTaxon
= null;
1317 if (taxonName
.isSpecies()){
1318 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1319 } else if (taxonName
.isInfraGeneric()){
1320 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1321 } else if (taxonName
.isInfraSpecific()){
1322 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1324 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1325 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1326 List
<String
> taxonNames
= new ArrayList
<String
>();
1328 for (TaxonNode node
: nodes
){
1329 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1330 // List<String> synonymsEpithet = new ArrayList<String>();
1332 if (node
.getClassification().equals(classification
)){
1333 if (!node
.isTopmostNode()){
1334 TaxonNode parent
= (TaxonNode
)node
.getParent();
1335 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1336 TaxonNameBase parentName
= parent
.getTaxon().getName();
1337 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1338 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1339 Rank rankOfTaxon
= taxonName
.getRank();
1342 //create inferred synonyms for species, subspecies
1343 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1345 Synonym inferredEpithet
= null;
1346 Synonym inferredGenus
= null;
1347 Synonym potentialCombination
= null;
1349 List
<String
> propertyPaths
= new ArrayList
<String
>();
1350 propertyPaths
.add("synonym");
1351 propertyPaths
.add("synonym.name");
1352 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1353 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1355 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1356 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1358 List
<TaxonRelationship
> taxonRelListParent
= null;
1359 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1360 if (doWithMisappliedNames
){
1361 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1362 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1366 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1367 Set
<String
> genusNames
= new HashSet
<String
>();
1369 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1370 Synonym syn
= synonymRelationOfParent
.getSynonym();
1372 inferredEpithet
= createInferredEpithets(taxon
,
1373 zooHashMap
, taxonName
, epithetOfTaxon
,
1374 infragenericEpithetOfTaxon
,
1375 infraspecificEpithetOfTaxon
,
1376 taxonNames
, parentName
,
1380 inferredSynonyms
.add(inferredEpithet
);
1381 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1382 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1385 if (doWithMisappliedNames
){
1387 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1388 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1390 inferredEpithet
= createInferredEpithets(taxon
,
1391 zooHashMap
, taxonName
, epithetOfTaxon
,
1392 infragenericEpithetOfTaxon
,
1393 infraspecificEpithetOfTaxon
,
1394 taxonNames
, parentName
,
1397 inferredSynonyms
.add(inferredEpithet
);
1398 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1399 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1403 if (!taxonNames
.isEmpty()){
1404 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1405 ZoologicalName name
;
1406 if (!synNotInCDM
.isEmpty()){
1407 inferredSynonymsToBeRemoved
.clear();
1409 for (Synonym syn
:inferredSynonyms
){
1410 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1411 if (!synNotInCDM
.contains(name
.getNameCache())){
1412 inferredSynonymsToBeRemoved
.add(syn
);
1416 // Remove identified Synonyms from inferredSynonyms
1417 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1418 inferredSynonyms
.remove(synonym
);
1423 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1426 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1427 TaxonNameBase synName
;
1428 ZoologicalName inferredSynName
;
1430 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1431 inferredGenus
= createInferredGenus(taxon
,
1432 zooHashMap
, taxonName
, epithetOfTaxon
,
1433 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1435 inferredSynonyms
.add(inferredGenus
);
1436 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1437 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1442 if (doWithMisappliedNames
){
1444 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1445 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1446 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1448 inferredSynonyms
.add(inferredGenus
);
1449 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1450 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1455 if (!taxonNames
.isEmpty()){
1456 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1457 ZoologicalName name
;
1458 if (!synNotInCDM
.isEmpty()){
1459 inferredSynonymsToBeRemoved
.clear();
1461 for (Synonym syn
:inferredSynonyms
){
1462 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1463 if (!synNotInCDM
.contains(name
.getNameCache())){
1464 inferredSynonymsToBeRemoved
.add(syn
);
1468 // Remove identified Synonyms from inferredSynonyms
1469 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1470 inferredSynonyms
.remove(synonym
);
1475 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1477 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1478 ZoologicalName inferredSynName
;
1479 //for all synonyms of the parent...
1480 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1481 TaxonNameBase synName
;
1482 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1483 synName
= synParent
.getName();
1485 HibernateProxyHelper
.deproxy(synParent
);
1487 // Set the sourceReference
1488 sourceReference
= synParent
.getSec();
1490 // Determine the idInSource
1491 String idInSourceParent
= getIdInSource(synParent
);
1493 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1494 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1495 String synParentInfragenericName
= null;
1496 String synParentSpecificEpithet
= null;
1498 if (parentSynZooName
.isInfraGeneric()){
1499 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1501 if (parentSynZooName
.isSpecies()){
1502 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1505 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1506 synonymsGenus.put(synGenusName, idInSource);
1509 //for all synonyms of the taxon
1511 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1513 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1514 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1515 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1517 synParentInfragenericName
,
1518 synParentSpecificEpithet
, syn
, 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());
1530 if (doWithMisappliedNames
){
1532 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1534 TaxonNameBase misappliedParentName
;
1536 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1537 misappliedParentName
= misappliedParent
.getName();
1539 HibernateProxyHelper
.deproxy(misappliedParent
);
1541 // Set the sourceReference
1542 sourceReference
= misappliedParent
.getSec();
1544 // Determine the idInSource
1545 String idInSourceParent
= getIdInSource(misappliedParent
);
1547 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1548 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1549 String synParentInfragenericName
= null;
1550 String synParentSpecificEpithet
= null;
1552 if (parentSynZooName
.isInfraGeneric()){
1553 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1555 if (parentSynZooName
.isSpecies()){
1556 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1560 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1561 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1562 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1563 potentialCombination
= createPotentialCombination(
1564 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1566 synParentInfragenericName
,
1567 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1570 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1571 inferredSynonyms
.add(potentialCombination
);
1572 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1573 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1578 if (!taxonNames
.isEmpty()){
1579 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1580 ZoologicalName name
;
1581 if (!synNotInCDM
.isEmpty()){
1582 inferredSynonymsToBeRemoved
.clear();
1583 for (Synonym syn
:inferredSynonyms
){
1585 name
= (ZoologicalName
) syn
.getName();
1586 }catch (ClassCastException e
){
1587 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1589 if (!synNotInCDM
.contains(name
.getNameCache())){
1590 inferredSynonymsToBeRemoved
.add(syn
);
1593 // Remove identified Synonyms from inferredSynonyms
1594 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1595 inferredSynonyms
.remove(synonym
);
1601 logger
.info("The synonymrelationship type is not defined.");
1602 return inferredSynonyms
;
1609 return inferredSynonyms
;
1612 private Synonym
createPotentialCombination(String idInSourceParent
,
1613 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1614 String synParentInfragenericName
, String synParentSpecificEpithet
,
1615 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1616 Synonym potentialCombination
;
1617 Reference sourceReference
;
1618 ZoologicalName inferredSynName
;
1619 HibernateProxyHelper
.deproxy(syn
);
1621 // Set sourceReference
1622 sourceReference
= syn
.getSec();
1623 if (sourceReference
== null){
1624 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1626 if (!parentSynZooName
.getTaxa().isEmpty()){
1627 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
1629 sourceReference
= taxon
.getSec();
1632 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1634 String synTaxonInfraSpecificName
= null;
1636 if (parentSynZooName
.isSpecies()){
1637 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1640 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1641 synonymsEpithet.add(epithetName);
1644 //create potential combinations...
1645 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1647 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1648 if (zooSynName
.isSpecies()){
1649 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1650 if (parentSynZooName
.isInfraGeneric()){
1651 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1654 if (zooSynName
.isInfraSpecific()){
1655 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1656 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1658 if (parentSynZooName
.isInfraGeneric()){
1659 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1663 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1665 // Set the sourceReference
1666 potentialCombination
.setSec(sourceReference
);
1669 // Determine the idInSource
1670 String idInSourceSyn
= getIdInSource(syn
);
1672 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1673 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1674 inferredSynName
.addSource(originalSource
);
1675 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1676 potentialCombination
.addSource(originalSource
);
1679 inferredSynName
.generateTitle();
1681 return potentialCombination
;
1684 private Synonym
createInferredGenus(Taxon taxon
,
1685 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1686 String epithetOfTaxon
, String genusOfTaxon
,
1687 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1690 Synonym inferredGenus
;
1691 TaxonNameBase synName
;
1692 ZoologicalName inferredSynName
;
1693 synName
=syn
.getName();
1694 HibernateProxyHelper
.deproxy(syn
);
1696 // Determine the idInSource
1697 String idInSourceSyn
= getIdInSource(syn
);
1698 String idInSourceTaxon
= getIdInSource(taxon
);
1699 // Determine the sourceReference
1700 Reference sourceReference
= syn
.getSec();
1702 //logger.warn(sourceReference.getTitleCache());
1704 synName
= syn
.getName();
1705 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1706 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1707 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1708 synonymsEpithet.add(synSpeciesEpithetName);
1711 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1712 //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...
1715 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1716 if (zooParentName
.isInfraGeneric()){
1717 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1720 if (taxonName
.isSpecies()){
1721 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1723 if (taxonName
.isInfraSpecific()){
1724 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1725 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1729 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1731 // Set the sourceReference
1732 inferredGenus
.setSec(sourceReference
);
1734 // Add the original source
1735 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1736 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1737 inferredGenus
.addSource(originalSource
);
1739 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1740 inferredSynName
.addSource(originalSource
);
1741 originalSource
= null;
1744 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
1745 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1746 inferredGenus
.addSource(originalSource
);
1748 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1749 inferredSynName
.addSource(originalSource
);
1750 originalSource
= null;
1753 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1755 inferredSynName
.generateTitle();
1758 return inferredGenus
;
1761 private Synonym
createInferredEpithets(Taxon taxon
,
1762 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1763 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1764 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1765 TaxonNameBase parentName
, TaxonBase syn
) {
1767 Synonym inferredEpithet
;
1768 TaxonNameBase synName
;
1769 ZoologicalName inferredSynName
;
1770 HibernateProxyHelper
.deproxy(syn
);
1772 // Determine the idInSource
1773 String idInSourceSyn
= getIdInSource(syn
);
1774 String idInSourceTaxon
= getIdInSource(taxon
);
1775 // Determine the sourceReference
1776 Reference sourceReference
= syn
.getSec();
1778 if (sourceReference
== null){
1779 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1781 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
1782 sourceReference
= taxon
.getSec();
1785 synName
= syn
.getName();
1786 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1787 String synGenusName
= zooSynName
.getGenusOrUninomial();
1788 String synInfraGenericEpithet
= null;
1789 String synSpecificEpithet
= null;
1791 if (zooSynName
.getInfraGenericEpithet() != null){
1792 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1795 if (zooSynName
.isInfraSpecific()){
1796 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1799 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1800 synonymsGenus.put(synGenusName, idInSource);
1803 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1805 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1806 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1807 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1809 inferredSynName
.setGenusOrUninomial(synGenusName
);
1811 if (parentName
.isInfraGeneric()){
1812 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1814 if (taxonName
.isSpecies()){
1815 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1816 }else if (taxonName
.isInfraSpecific()){
1817 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1818 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1821 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1823 // Set the sourceReference
1824 inferredEpithet
.setSec(sourceReference
);
1826 /* Add the original source
1827 if (idInSource != null) {
1828 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1831 Reference citation = getCitation(syn);
1832 if (citation != null) {
1833 originalSource.setCitation(citation);
1834 inferredEpithet.addSource(originalSource);
1837 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1839 IdentifiableSource originalSource
;
1840 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1842 inferredEpithet
.addSource(originalSource
);
1844 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1846 inferredSynName
.addSource(originalSource
);
1850 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1852 inferredSynName
.generateTitle();
1853 return inferredEpithet
;
1857 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1858 * Very likely only useful for createInferredSynonyms().
1863 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1864 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1865 if (taxonName
== null) {
1866 taxonName
= zooHashMap
.get(uuid
);
1872 * Returns the idInSource for a given Synonym.
1875 private String
getIdInSource(TaxonBase taxonBase
) {
1876 String idInSource
= null;
1877 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1878 if (sources
.size() == 1) {
1879 IdentifiableSource source
= sources
.iterator().next();
1880 if (source
!= null) {
1881 idInSource
= source
.getIdInSource();
1883 } else if (sources
.size() > 1) {
1886 for (IdentifiableSource source
: sources
) {
1887 idInSource
+= source
.getIdInSource();
1888 if (count
< sources
.size()) {
1893 } else if (sources
.size() == 0){
1894 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
1903 * Returns the citation for a given Synonym.
1906 private Reference
getCitation(Synonym syn
) {
1907 Reference citation
= null;
1908 Set
<IdentifiableSource
> sources
= syn
.getSources();
1909 if (sources
.size() == 1) {
1910 IdentifiableSource source
= sources
.iterator().next();
1911 if (source
!= null) {
1912 citation
= source
.getCitation();
1914 } else if (sources
.size() > 1) {
1915 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1921 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1922 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1924 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1925 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1926 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1928 return inferredSynonyms
;