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
.Arrays
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
20 import java
.util
.UUID
;
22 import org
.apache
.log4j
.Logger
;
23 import org
.apache
.lucene
.index
.CorruptIndexException
;
24 import org
.apache
.lucene
.queryParser
.ParseException
;
25 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
26 import org
.apache
.lucene
.search
.BooleanQuery
;
27 import org
.apache
.lucene
.search
.Query
;
28 import org
.apache
.lucene
.search
.SortField
;
29 import org
.apache
.lucene
.search
.TopDocs
;
30 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
31 import org
.springframework
.stereotype
.Service
;
32 import org
.springframework
.transaction
.annotation
.Propagation
;
33 import org
.springframework
.transaction
.annotation
.Transactional
;
35 import eu
.etaxonomy
.cdm
.api
.service
.config
.IFindTaxaAndNamesConfigurator
;
36 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
37 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
38 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
39 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
40 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
41 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
42 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
43 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
44 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
45 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearch
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
49 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
50 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
51 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
52 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
53 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
54 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
55 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
56 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
57 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
58 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
59 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
60 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
61 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
62 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
63 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
64 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
65 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
66 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
67 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
68 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
69 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
70 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
71 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
72 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
73 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
74 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
75 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
76 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
77 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
78 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
79 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
80 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
81 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
82 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
83 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
84 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
85 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
86 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
87 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
88 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
89 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
90 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
91 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
92 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
93 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
94 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
95 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
99 * @author a.kohlbecker
104 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
105 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
106 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
108 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
110 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
112 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
116 private ITaxonNameDao nameDao
;
119 private INameService nameService
;
122 private ICdmGenericDao genericDao
;
125 private IDescriptionService descriptionService
;
128 private IOrderedTermVocabularyDao orderedVocabularyDao
;
133 public TaxonServiceImpl(){
134 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
138 * FIXME Candidate for harmonization
139 * rename searchByName ?
141 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
142 return dao
.getTaxaByName(name
, sec
);
146 * FIXME Candidate for harmonization
147 * list(Synonym.class, ...)
149 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
151 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
152 return dao
.getAllSynonyms(limit
, start
);
156 * FIXME Candidate for harmonization
157 * list(Taxon.class, ...)
159 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
161 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
162 return dao
.getAllTaxa(limit
, start
);
166 * FIXME Candidate for harmonization
167 * merge with getRootTaxa(Reference sec, ..., ...)
169 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
171 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
172 if (cdmFetch
== null){
173 cdmFetch
= CdmFetch
.NO_FETCH();
175 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
180 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
182 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
183 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
187 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
189 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
190 return dao
.getAllRelationships(limit
, start
);
194 * FIXME Candidate for harmonization
195 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
198 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
200 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
201 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
202 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
203 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
204 return taxonRelTypeVocabulary
;
211 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
213 @Transactional(readOnly
= false)
214 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
216 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
217 synonymName
.removeTaxonBase(synonym
);
218 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
219 taxonName
.removeTaxonBase(acceptedTaxon
);
221 synonym
.setName(taxonName
);
222 acceptedTaxon
.setName(synonymName
);
224 // the accepted taxon needs a new uuid because the concept has changed
225 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
226 //acceptedTaxon.setUuid(UUID.randomUUID());
231 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
233 //TODO correct delete handling still needs to be implemented / checked
235 @Transactional(readOnly
= false)
236 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
238 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
239 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
240 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
242 //check synonym is not homotypic
243 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
244 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
245 throw new HomotypicalGroupChangeException(message
);
248 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
250 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
251 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
253 for (Synonym heteroSynonym
: heteroSynonyms
){
254 if (synonym
.equals(heteroSynonym
)){
255 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
257 //move synonyms in same homotypic group to new accepted taxon
258 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
262 //synonym.getName().removeTaxonBase(synonym);
263 //TODO correct delete handling still needs to be implemented / checked
265 // deleteSynonym(synonym, taxon, false);
268 this.delete(synonym
);
270 } catch (Exception e
) {
271 logger
.info("Can't delete old synonym from database");
275 return newAcceptedTaxon
;
279 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
281 // Get name from synonym
282 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
284 // remove synonym from taxon
285 toTaxon
.removeSynonym(synonym
);
287 // Create a taxon with synonym name
288 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
290 // Add taxon relation
291 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
293 // since we are swapping names, we have to detach the name from the synonym completely.
294 // Otherwise the synonym will still be in the list of typified names.
295 synonym
.getName().removeTaxonBase(synonym
);
302 * @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)
304 @Transactional(readOnly
= false)
306 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
307 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
309 TaxonNameBase synonymName
= synonym
.getName();
310 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
314 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
315 newHomotypicalGroup
.addTypifiedName(synonymName
);
317 //remove existing basionym relationships
318 synonymName
.removeBasionyms();
320 //add basionym relationship
321 if (setBasionymRelationIfApplicable
){
322 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
323 for (TaxonNameBase basionym
: basionyms
){
324 synonymName
.addBasionym(basionym
);
328 //set synonym relationship correctly
329 // SynonymRelationship relToTaxon = null;
330 boolean relToTargetTaxonExists
= false;
331 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
332 for (SynonymRelationship rel
: existingRelations
){
333 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
334 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
335 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
336 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
337 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
338 rel
.setType(newRelationType
);
339 //TODO handle citation and microCitation
342 relToTargetTaxonExists
= true;
344 if (removeFromOtherTaxa
){
345 acceptedTaxon
.removeSynonym(synonym
, false);
351 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
352 Taxon acceptedTaxon
= targetTaxon
;
353 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
354 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
355 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
356 //TODO handle citation and microCitation
357 Reference citation
= null;
358 String microCitation
= null;
359 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
366 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
369 @Transactional(readOnly
= false)
370 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
372 clazz
= TaxonBase
.class;
374 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
378 protected void setDao(ITaxonDao dao
) {
383 * @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)
385 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
386 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
388 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
389 if(numberOfResults
> 0) { // no point checking again
390 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
393 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
397 * @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)
399 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
400 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
402 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
403 if(numberOfResults
> 0) { // no point checking again
404 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
411 * @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)
413 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
414 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
416 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
417 if(numberOfResults
> 0) { // no point checking again
418 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
424 * @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)
426 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
427 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
429 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
430 if(numberOfResults
> 0) { // no point checking again
431 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
433 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
437 * @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)
439 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
440 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
442 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
443 if(numberOfResults
> 0) { // no point checking again
444 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
450 * @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)
452 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
453 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
455 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
456 if(numberOfResults
> 0) { // no point checking again
457 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
459 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
463 * @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)
465 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
466 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
468 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
469 if(numberOfResults
> 0) { // no point checking again
470 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
473 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
477 * @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)
479 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
480 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
482 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
483 if(numberOfResults
> 0) { // no point checking again
484 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
487 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
491 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
493 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
494 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
495 return t
.getHomotypicSynonymsByHomotypicGroup();
499 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
501 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
502 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
503 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
504 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
505 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
506 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
508 return heterotypicSynonymyGroups
;
511 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
513 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
514 // Class<? extends TaxonBase> clazz = null;
515 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
516 // clazz = TaxonBase.class;
517 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
518 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
519 // } else if(configurator.isDoTaxa()) {
520 // clazz = Taxon.class;
521 // //propertyPath = configurator.getTaxonPropertyPath();
522 // } else if (configurator.isDoSynonyms()) {
523 // clazz = Synonym.class;
524 // //propertyPath = configurator.getSynonymPropertyPath();
528 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
533 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
535 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
537 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
538 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
539 List
<TaxonBase
> taxa
= null;
542 long numberTaxaResults
= 0L;
545 List
<String
> propertyPath
= new ArrayList
<String
>();
546 if(configurator
.getTaxonPropertyPath() != null){
547 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
551 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
552 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
554 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
555 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
556 configurator
.getNamedAreas());
559 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
560 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
561 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
562 configurator
.getMatchMode(), configurator
.getNamedAreas(),
563 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
567 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
570 results
.addAll(taxa
);
573 numberOfResults
+= numberTaxaResults
;
575 // Names without taxa
576 if (configurator
.isDoNamesWithoutTaxa()) {
577 int numberNameResults
= 0;
579 List
<?
extends TaxonNameBase
<?
,?
>> names
=
580 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
581 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
582 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
583 if (names
.size() > 0) {
584 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
585 if (taxonName
.getTaxonBases().size() == 0) {
586 results
.add(taxonName
);
590 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
591 numberOfResults
+= numberNameResults
;
595 // Taxa from common names
597 if (configurator
.isDoTaxaByCommonNames()) {
598 taxa
= new ArrayList
<TaxonBase
>();
599 numberTaxaResults
= 0;
600 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
601 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
603 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
604 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
605 for( Object
[] entry
: commonNameResults
) {
606 taxa
.add((TaxonBase
) entry
[0]);
610 results
.addAll(taxa
);
612 numberOfResults
+= numberTaxaResults
;
616 return new DefaultPagerImpl
<IdentifiableEntity
>
617 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
620 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
621 return dao
.getUuidAndTitleCache();
625 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
627 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
628 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
629 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
630 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
631 for (TaxonDescription taxDesc
: descriptions
){
632 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
633 for (DescriptionElementBase descElem
: elements
){
634 for(Media media
: descElem
.getMedia()){
636 //find the best matching representation
637 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
646 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
648 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, boolean limitToGalleries
, List
<String
> propertyPath
){
650 Pager
<TaxonDescription
> p
=
651 descriptionService
.getTaxonDescriptions(taxon
, null, null, null, null, propertyPath
);
653 // pars the media and quality parameters
656 // collect all media of the given taxon
657 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
658 List
<Media
> taxonGalleryMedia
= new ArrayList
<Media
>();
659 for(TaxonDescription desc
: p
.getRecords()){
661 if(desc
.isImageGallery()){
662 for(DescriptionElementBase element
: desc
.getElements()){
663 for(Media media
: element
.getMedia()){
664 taxonGalleryMedia
.add(media
);
667 } else if(!limitToGalleries
){
668 for(DescriptionElementBase element
: desc
.getElements()){
669 for(Media media
: element
.getMedia()){
670 taxonMedia
.add(media
);
677 taxonGalleryMedia
.addAll(taxonMedia
);
678 return taxonGalleryMedia
;
682 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
684 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
685 return this.dao
.findById(listOfIDs
);
689 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
691 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
692 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
696 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
698 public int countAllRelationships() {
699 return this.dao
.countAllRelationships();
706 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
708 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
709 return this.dao
.findIdenticalTaxonNames(propertyPath
);
714 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
717 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
719 config
= new TaxonDeletionConfigurator();
723 if (! config
.isDeleteTaxonNodes()){
724 if (taxon
.getTaxonNodes().size() > 0){
725 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
726 throw new ReferencedObjectUndeletableException(message
);
731 // SynonymRelationShip
732 if (config
.isDeleteSynonymRelations()){
733 boolean removeSynonymNameFromHomotypicalGroup
= false;
734 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
735 Synonym synonym
= synRel
.getSynonym();
736 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
737 if (config
.isDeleteSynonymsIfPossible()){
739 boolean newHomotypicGroupIfNeeded
= true;
740 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
742 deleteSynonymRelationships(synonym
, taxon
);
748 if (! config
.isDeleteTaxonRelationships()){
749 if (taxon
.getTaxonRelations().size() > 0){
750 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.";
751 throw new ReferencedObjectUndeletableException(message
);
757 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
759 for (TaxonDescription desc
: descriptions
){
760 if (config
.isDeleteDescriptions()){
761 //TODO use description delete configurator ?
762 //FIXME check if description is ALWAYS deletable
763 descriptionService
.delete(desc
);
765 if (desc
.getDescribedSpecimenOrObservations().size()>0){
766 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
767 " which also describes specimens or abservations";
768 throw new ReferencedObjectUndeletableException(message
);
774 //check references with only reverse mapping
775 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
776 for (CdmBase referencingObject
: referencingObjects
){
777 //IIdentificationKeys (Media, Polytomous, MultiAccess)
778 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
779 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
780 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
781 throw new ReferencedObjectUndeletableException(message
);
786 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
787 String message
= "Taxon can't be deleted as it is used in polytomous key node";
788 throw new ReferencedObjectUndeletableException(message
);
792 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
793 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
794 throw new ReferencedObjectUndeletableException(message
);
800 if (config
.isDeleteNameIfPossible()){
802 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
803 } catch (ReferencedObjectUndeletableException e
) {
805 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
812 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
814 @Transactional(readOnly
= false)
816 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
817 if (synonym
== null){
820 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
822 //remove synonymRelationship
823 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
827 taxonSet
.addAll(synonym
.getAcceptedTaxa());
829 for (Taxon relatedTaxon
: taxonSet
){
830 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
831 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
833 this.saveOrUpdate(synonym
);
835 //TODO remove name from homotypical group?
837 //remove synonym (if necessary)
838 if (synonym
.getSynonymRelations().isEmpty()){
839 TaxonNameBase
<?
,?
> name
= synonym
.getName();
840 synonym
.setName(null);
843 //remove name if possible (and required)
844 if (name
!= null && removeNameIfPossible
){
846 nameService
.delete(name
, new NameDeletionConfigurator());
847 }catch (DataChangeNoRollbackException ex
){
848 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
856 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
858 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
860 return this.dao
.findIdenticalNamesNew(propertyPath
);
864 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
866 public String
getPhylumName(TaxonNameBase name
){
867 return this.dao
.getPhylumName(name
);
871 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
873 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
874 return dao
.deleteSynonymRelationships(syn
, taxon
);
878 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
880 public long deleteSynonymRelationships(Synonym syn
) {
881 return dao
.deleteSynonymRelationships(syn
, null);
886 * @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)
888 public List
<SynonymRelationship
> listSynonymRelationships(
889 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
890 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
891 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
893 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
894 if(numberOfResults
> 0) { // no point checking again
895 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
901 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
904 public Taxon
findBestMatchingTaxon(String taxonName
) {
905 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
906 config
.setTaxonNameTitle(taxonName
);
907 return findBestMatchingTaxon(config
);
913 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
915 Taxon bestCandidate
= null;
917 // 1. search for acceptet taxa
918 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
919 boolean bestCandidateMatchesSecUuid
= false;
920 boolean bestCandidateIsInClassification
= false;
921 int countEqualCandidates
= 0;
922 for(TaxonBase taxonBaseCandidate
: taxonList
){
923 if(taxonBaseCandidate
instanceof Taxon
){
924 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
925 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
926 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
928 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
929 bestCandidate
= newCanditate
;
930 countEqualCandidates
= 1;
931 bestCandidateMatchesSecUuid
= true;
935 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
936 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
938 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
939 bestCandidate
= newCanditate
;
940 countEqualCandidates
= 1;
941 bestCandidateIsInClassification
= true;
944 if (bestCandidate
== null){
945 bestCandidate
= newCanditate
;
946 countEqualCandidates
= 1;
950 }else{ //not Taxon.class
953 countEqualCandidates
++;
956 if (bestCandidate
!= null){
957 if(countEqualCandidates
> 1){
958 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
959 return bestCandidate
;
961 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
962 return bestCandidate
;
967 // 2. search for synonyms
968 if (config
.isIncludeSynonyms()){
969 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
970 for(TaxonBase taxonBase
: synonymList
){
971 if(taxonBase
instanceof Synonym
){
972 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
973 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
974 if(!acceptetdCandidates
.isEmpty()){
975 bestCandidate
= acceptetdCandidates
.iterator().next();
976 if(acceptetdCandidates
.size() == 1){
977 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
978 return bestCandidate
;
980 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
981 return bestCandidate
;
983 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
989 } catch (Exception e
){
993 return bestCandidate
;
996 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
997 UUID configClassificationUuid
= config
.getClassificationUuid();
998 if (configClassificationUuid
== null){
1001 for (TaxonNode node
: taxon
.getTaxonNodes()){
1002 UUID classUuid
= node
.getClassification().getUuid();
1003 if (configClassificationUuid
.equals(classUuid
)){
1010 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1011 UUID configSecUuid
= config
.getSecUuid();
1012 if (configSecUuid
== null){
1015 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1016 return configSecUuid
.equals(taxonSecUuid
);
1020 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1023 public Synonym
findBestMatchingSynonym(String taxonName
) {
1024 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1025 if(! synonymList
.isEmpty()){
1026 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1027 if(synonymList
.size() == 1){
1028 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1031 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1040 * @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)
1043 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1044 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1046 Synonym synonym
= oldSynonymRelation
.getSynonym();
1047 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1048 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1049 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1050 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1051 //set default relationship type
1052 if (newSynonymRelationshipType
== null){
1053 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1055 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1057 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1058 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1059 boolean isSingleInGroup
= !(hgSize
> 1);
1061 if (! isSingleInGroup
){
1062 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1063 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1064 if (isHomotypicToAccepted
){
1065 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.";
1066 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1067 message
= String
.format(message
, homotypicRelatives
);
1068 throw new HomotypicalGroupChangeException(message
);
1070 if (! moveHomotypicGroup
){
1071 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.";
1072 throw new HomotypicalGroupChangeException(message
);
1075 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1077 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1079 SynonymRelationship result
= null;
1080 //move all synonyms to new taxon
1081 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1082 for (Synonym syn
: homotypicSynonyms
){
1083 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1084 for (SynonymRelationship synRelation
: synRelations
){
1085 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1086 Reference
<?
> newReference
= reference
;
1087 if (newReference
== null && keepReference
){
1088 newReference
= synRelation
.getCitation();
1090 String newRefDetail
= referenceDetail
;
1091 if (newRefDetail
== null && keepReference
){
1092 newRefDetail
= synRelation
.getCitationMicroReference();
1094 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1095 fromTaxon
.removeSynonymRelation(synRelation
, false);
1097 //change homotypic group of synonym if relType is 'homotypic'
1098 // if (newRelTypeIsHomotypic){
1099 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1102 if (synRelation
.equals(oldSynonymRelation
)){
1103 result
= newSynRelation
;
1109 saveOrUpdate(newTaxon
);
1110 //Assert that there is a result
1111 if (result
== null){
1112 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1113 throw new IllegalStateException(message
);
1119 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1122 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1123 return dao
.getUuidAndTitleCacheTaxon();
1127 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1130 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1131 return dao
.getUuidAndTitleCacheSynonym();
1135 * @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)
1138 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1139 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1140 Classification classification
, List
<Language
> languages
,
1141 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1144 LuceneSearch luceneSearch
= prepareFindByFullTextSearch(clazz
, queryString
, classification
, languages
, highlightFragments
);
1146 // --- execute search
1147 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1149 // --- initialize taxa, thighlight matches ....
1150 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1151 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1152 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, "taxon.id", propertyPaths
);
1154 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, topDocsResultSet
.totalHits
, pageSize
, searchResults
);
1159 * @param queryString
1160 * @param classification
1162 * @param highlightFragments
1163 * @param directorySelectClass
1166 protected LuceneSearch
prepareFindByFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Language
> languages
,
1167 boolean highlightFragments
) {
1168 BooleanQuery finalQuery
= new BooleanQuery();
1169 BooleanQuery textQuery
= new BooleanQuery();
1171 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), TaxonBase
.class);
1172 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1174 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", false)};
1175 luceneSearch
.setSortFields(sortFields
);
1177 // ---- search criteria
1178 luceneSearch
.setClazz(clazz
);
1180 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1181 textQuery
.add(queryFactory
.newDefinedTermBaseQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1183 finalQuery
.add(textQuery
, Occur
.MUST
);
1185 if(classification
!= null){
1186 finalQuery
.add(queryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1188 luceneSearch
.setQuery(finalQuery
);
1190 if(highlightFragments
){
1191 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1193 return luceneSearch
;
1198 * @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)
1201 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1202 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1203 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1204 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1207 LuceneSearch luceneSearch
= prepareByDescriptionElementFullTextSearch(clazz
, queryString
, classification
, features
, languages
, highlightFragments
);
1209 // --- execute search
1210 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1212 // --- initialize taxa, thighlight matches ....
1213 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1214 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1215 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, "inDescription.taxon.id", propertyPaths
);
1217 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, topDocsResultSet
.totalHits
, pageSize
, searchResults
);
1222 public Pager
<SearchResult
<TaxonBase
>> findByEveryThingFullText(String queryString
,
1223 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1224 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
1225 , List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1227 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, features
, languages
, highlightFragments
);
1228 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
);
1230 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
1232 // --- execute search
1233 TopDocs topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1235 // --- initialize taxa, thighlight matches ....
1236 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1237 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1238 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, "inDescription.taxon.id", propertyPaths
);
1240 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, topDocsResultSet
.totalHits
, pageSize
, searchResults
);
1247 * @param queryString
1248 * @param classification
1251 * @param highlightFragments
1252 * @param directorySelectClass
1255 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Feature
> features
,
1256 List
<Language
> languages
, boolean highlightFragments
) {
1257 BooleanQuery finalQuery
= new BooleanQuery();
1258 BooleanQuery textQuery
= new BooleanQuery();
1260 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), DescriptionElementBase
.class);
1261 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1263 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", false)};
1264 luceneSearch
.setSortFields(sortFields
);
1266 // ---- search criteria
1267 luceneSearch
.setClazz(clazz
);
1268 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1272 if(languages
== null || languages
.size() == 0){
1273 nameQuery
= queryFactory
.newTermQuery("name", queryString
);
1275 nameQuery
= new BooleanQuery();
1276 BooleanQuery languageSubQuery
= new BooleanQuery();
1277 for(Language lang
: languages
){
1278 languageSubQuery
.add(queryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString()), Occur
.SHOULD
);
1280 ((BooleanQuery
) nameQuery
).add(queryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
1281 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1283 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1286 // text field from TextData
1287 textQuery
.add(queryFactory
.newLocalizedTermQuery("text", queryString
, languages
), Occur
.SHOULD
);
1289 // --- TermBase fields - by representation ----
1290 // state field from CategoricalData
1291 textQuery
.add(queryFactory
.newLocalizedTermQuery("states.state.representation", queryString
, languages
), Occur
.SHOULD
);
1293 // state field from CategoricalData
1294 textQuery
.add(queryFactory
.newLocalizedTermQuery("states.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1296 finalQuery
.add(textQuery
, Occur
.MUST
);
1297 // --- classification ----
1299 if(classification
!= null){
1300 finalQuery
.add(queryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
1303 // --- IdentifieableEntity fields - by uuid
1304 if(features
!= null && features
.size() > 0 ){
1305 finalQuery
.add(queryFactory
.newEntityUuidQuery("feature.uuid", features
), Occur
.MUST
);
1308 // the description must be associated with a taxon
1309 finalQuery
.add(queryFactory
.newIdNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
1311 luceneSearch
.setQuery(finalQuery
);
1313 if(highlightFragments
){
1314 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1316 return luceneSearch
;
1320 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1321 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1322 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1324 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1325 * or {@link MultilanguageTextFieldBridge }
1326 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1327 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1328 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1330 * TODO move to utiliy class !!!!!!!!
1332 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1334 if(stringBuilder
== null){
1335 stringBuilder
= new StringBuilder();
1337 if(languages
== null || languages
.size() == 0){
1338 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
1340 for(Language lang
: languages
){
1341 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
1344 return stringBuilder
;
1347 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1348 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1349 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1351 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1354 UUID uuid
= taxon
.getName().getUuid();
1355 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1356 String epithetOfTaxon
= null;
1357 String infragenericEpithetOfTaxon
= null;
1358 String infraspecificEpithetOfTaxon
= null;
1359 if (taxonName
.isSpecies()){
1360 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1361 } else if (taxonName
.isInfraGeneric()){
1362 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1363 } else if (taxonName
.isInfraSpecific()){
1364 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1366 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1367 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1368 List
<String
> taxonNames
= new ArrayList
<String
>();
1370 for (TaxonNode node
: nodes
){
1371 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1372 // List<String> synonymsEpithet = new ArrayList<String>();
1374 if (node
.getClassification().equals(classification
)){
1375 if (!node
.isTopmostNode()){
1376 TaxonNode parent
= (TaxonNode
)node
.getParent();
1377 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1378 TaxonNameBase parentName
= parent
.getTaxon().getName();
1379 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1380 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1381 Rank rankOfTaxon
= taxonName
.getRank();
1384 //create inferred synonyms for species, subspecies
1385 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1387 Synonym inferredEpithet
= null;
1388 Synonym inferredGenus
= null;
1389 Synonym potentialCombination
= null;
1391 List
<String
> propertyPaths
= new ArrayList
<String
>();
1392 propertyPaths
.add("synonym");
1393 propertyPaths
.add("synonym.name");
1394 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1395 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1397 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1398 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1400 List
<TaxonRelationship
> taxonRelListParent
= null;
1401 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1402 if (doWithMisappliedNames
){
1403 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1404 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1408 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1409 Set
<String
> genusNames
= new HashSet
<String
>();
1411 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1412 Synonym syn
= synonymRelationOfParent
.getSynonym();
1414 inferredEpithet
= createInferredEpithets(taxon
,
1415 zooHashMap
, taxonName
, epithetOfTaxon
,
1416 infragenericEpithetOfTaxon
,
1417 infraspecificEpithetOfTaxon
,
1418 taxonNames
, parentName
,
1422 inferredSynonyms
.add(inferredEpithet
);
1423 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1424 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1427 if (doWithMisappliedNames
){
1429 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1430 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1432 inferredEpithet
= createInferredEpithets(taxon
,
1433 zooHashMap
, taxonName
, epithetOfTaxon
,
1434 infragenericEpithetOfTaxon
,
1435 infraspecificEpithetOfTaxon
,
1436 taxonNames
, parentName
,
1439 inferredSynonyms
.add(inferredEpithet
);
1440 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1441 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1445 if (!taxonNames
.isEmpty()){
1446 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1447 ZoologicalName name
;
1448 if (!synNotInCDM
.isEmpty()){
1449 inferredSynonymsToBeRemoved
.clear();
1451 for (Synonym syn
:inferredSynonyms
){
1452 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1453 if (!synNotInCDM
.contains(name
.getNameCache())){
1454 inferredSynonymsToBeRemoved
.add(syn
);
1458 // Remove identified Synonyms from inferredSynonyms
1459 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1460 inferredSynonyms
.remove(synonym
);
1465 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1468 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1469 TaxonNameBase synName
;
1470 ZoologicalName inferredSynName
;
1472 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1473 inferredGenus
= createInferredGenus(taxon
,
1474 zooHashMap
, taxonName
, epithetOfTaxon
,
1475 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1477 inferredSynonyms
.add(inferredGenus
);
1478 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1479 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1484 if (doWithMisappliedNames
){
1486 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1487 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1488 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1490 inferredSynonyms
.add(inferredGenus
);
1491 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1492 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1497 if (!taxonNames
.isEmpty()){
1498 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1499 ZoologicalName name
;
1500 if (!synNotInCDM
.isEmpty()){
1501 inferredSynonymsToBeRemoved
.clear();
1503 for (Synonym syn
:inferredSynonyms
){
1504 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1505 if (!synNotInCDM
.contains(name
.getNameCache())){
1506 inferredSynonymsToBeRemoved
.add(syn
);
1510 // Remove identified Synonyms from inferredSynonyms
1511 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1512 inferredSynonyms
.remove(synonym
);
1517 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1519 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1520 ZoologicalName inferredSynName
;
1521 //for all synonyms of the parent...
1522 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1523 TaxonNameBase synName
;
1524 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1525 synName
= synParent
.getName();
1527 HibernateProxyHelper
.deproxy(synParent
);
1529 // Set the sourceReference
1530 sourceReference
= synParent
.getSec();
1532 // Determine the idInSource
1533 String idInSourceParent
= getIdInSource(synParent
);
1535 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1536 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1537 String synParentInfragenericName
= null;
1538 String synParentSpecificEpithet
= null;
1540 if (parentSynZooName
.isInfraGeneric()){
1541 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1543 if (parentSynZooName
.isSpecies()){
1544 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1547 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1548 synonymsGenus.put(synGenusName, idInSource);
1551 //for all synonyms of the taxon
1553 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1555 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1556 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1557 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1559 synParentInfragenericName
,
1560 synParentSpecificEpithet
, syn
, zooHashMap
);
1562 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1563 inferredSynonyms
.add(potentialCombination
);
1564 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1565 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1572 if (doWithMisappliedNames
){
1574 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1576 TaxonNameBase misappliedParentName
;
1578 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1579 misappliedParentName
= misappliedParent
.getName();
1581 HibernateProxyHelper
.deproxy(misappliedParent
);
1583 // Set the sourceReference
1584 sourceReference
= misappliedParent
.getSec();
1586 // Determine the idInSource
1587 String idInSourceParent
= getIdInSource(misappliedParent
);
1589 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1590 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1591 String synParentInfragenericName
= null;
1592 String synParentSpecificEpithet
= null;
1594 if (parentSynZooName
.isInfraGeneric()){
1595 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1597 if (parentSynZooName
.isSpecies()){
1598 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1602 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1603 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1604 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1605 potentialCombination
= createPotentialCombination(
1606 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1608 synParentInfragenericName
,
1609 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1612 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1613 inferredSynonyms
.add(potentialCombination
);
1614 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1615 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1620 if (!taxonNames
.isEmpty()){
1621 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1622 ZoologicalName name
;
1623 if (!synNotInCDM
.isEmpty()){
1624 inferredSynonymsToBeRemoved
.clear();
1625 for (Synonym syn
:inferredSynonyms
){
1627 name
= (ZoologicalName
) syn
.getName();
1628 }catch (ClassCastException e
){
1629 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1631 if (!synNotInCDM
.contains(name
.getNameCache())){
1632 inferredSynonymsToBeRemoved
.add(syn
);
1635 // Remove identified Synonyms from inferredSynonyms
1636 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1637 inferredSynonyms
.remove(synonym
);
1643 logger
.info("The synonymrelationship type is not defined.");
1644 return inferredSynonyms
;
1651 return inferredSynonyms
;
1654 private Synonym
createPotentialCombination(String idInSourceParent
,
1655 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1656 String synParentInfragenericName
, String synParentSpecificEpithet
,
1657 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1658 Synonym potentialCombination
;
1659 Reference sourceReference
;
1660 ZoologicalName inferredSynName
;
1661 HibernateProxyHelper
.deproxy(syn
);
1663 // Set sourceReference
1664 sourceReference
= syn
.getSec();
1665 if (sourceReference
== null){
1666 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1668 if (!parentSynZooName
.getTaxa().isEmpty()){
1669 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
1671 sourceReference
= taxon
.getSec();
1674 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1676 String synTaxonInfraSpecificName
= null;
1678 if (parentSynZooName
.isSpecies()){
1679 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1682 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1683 synonymsEpithet.add(epithetName);
1686 //create potential combinations...
1687 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1689 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1690 if (zooSynName
.isSpecies()){
1691 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1692 if (parentSynZooName
.isInfraGeneric()){
1693 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1696 if (zooSynName
.isInfraSpecific()){
1697 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1698 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1700 if (parentSynZooName
.isInfraGeneric()){
1701 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1705 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1707 // Set the sourceReference
1708 potentialCombination
.setSec(sourceReference
);
1711 // Determine the idInSource
1712 String idInSourceSyn
= getIdInSource(syn
);
1714 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1715 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1716 inferredSynName
.addSource(originalSource
);
1717 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1718 potentialCombination
.addSource(originalSource
);
1721 inferredSynName
.generateTitle();
1723 return potentialCombination
;
1726 private Synonym
createInferredGenus(Taxon taxon
,
1727 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1728 String epithetOfTaxon
, String genusOfTaxon
,
1729 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1732 Synonym inferredGenus
;
1733 TaxonNameBase synName
;
1734 ZoologicalName inferredSynName
;
1735 synName
=syn
.getName();
1736 HibernateProxyHelper
.deproxy(syn
);
1738 // Determine the idInSource
1739 String idInSourceSyn
= getIdInSource(syn
);
1740 String idInSourceTaxon
= getIdInSource(taxon
);
1741 // Determine the sourceReference
1742 Reference sourceReference
= syn
.getSec();
1744 //logger.warn(sourceReference.getTitleCache());
1746 synName
= syn
.getName();
1747 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1748 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1749 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1750 synonymsEpithet.add(synSpeciesEpithetName);
1753 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1754 //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...
1757 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1758 if (zooParentName
.isInfraGeneric()){
1759 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1762 if (taxonName
.isSpecies()){
1763 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1765 if (taxonName
.isInfraSpecific()){
1766 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1767 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1771 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1773 // Set the sourceReference
1774 inferredGenus
.setSec(sourceReference
);
1776 // Add the original source
1777 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1778 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1779 inferredGenus
.addSource(originalSource
);
1781 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1782 inferredSynName
.addSource(originalSource
);
1783 originalSource
= null;
1786 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
1787 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1788 inferredGenus
.addSource(originalSource
);
1790 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1791 inferredSynName
.addSource(originalSource
);
1792 originalSource
= null;
1795 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1797 inferredSynName
.generateTitle();
1800 return inferredGenus
;
1803 private Synonym
createInferredEpithets(Taxon taxon
,
1804 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1805 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1806 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1807 TaxonNameBase parentName
, TaxonBase syn
) {
1809 Synonym inferredEpithet
;
1810 TaxonNameBase synName
;
1811 ZoologicalName inferredSynName
;
1812 HibernateProxyHelper
.deproxy(syn
);
1814 // Determine the idInSource
1815 String idInSourceSyn
= getIdInSource(syn
);
1816 String idInSourceTaxon
= getIdInSource(taxon
);
1817 // Determine the sourceReference
1818 Reference sourceReference
= syn
.getSec();
1820 if (sourceReference
== null){
1821 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1823 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
1824 sourceReference
= taxon
.getSec();
1827 synName
= syn
.getName();
1828 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1829 String synGenusName
= zooSynName
.getGenusOrUninomial();
1830 String synInfraGenericEpithet
= null;
1831 String synSpecificEpithet
= null;
1833 if (zooSynName
.getInfraGenericEpithet() != null){
1834 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1837 if (zooSynName
.isInfraSpecific()){
1838 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1841 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1842 synonymsGenus.put(synGenusName, idInSource);
1845 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1847 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1848 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1849 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1851 inferredSynName
.setGenusOrUninomial(synGenusName
);
1853 if (parentName
.isInfraGeneric()){
1854 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1856 if (taxonName
.isSpecies()){
1857 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1858 }else if (taxonName
.isInfraSpecific()){
1859 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1860 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1863 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1865 // Set the sourceReference
1866 inferredEpithet
.setSec(sourceReference
);
1868 /* Add the original source
1869 if (idInSource != null) {
1870 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1873 Reference citation = getCitation(syn);
1874 if (citation != null) {
1875 originalSource.setCitation(citation);
1876 inferredEpithet.addSource(originalSource);
1879 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1881 IdentifiableSource originalSource
;
1882 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1884 inferredEpithet
.addSource(originalSource
);
1886 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1888 inferredSynName
.addSource(originalSource
);
1892 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1894 inferredSynName
.generateTitle();
1895 return inferredEpithet
;
1899 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1900 * Very likely only useful for createInferredSynonyms().
1905 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1906 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1907 if (taxonName
== null) {
1908 taxonName
= zooHashMap
.get(uuid
);
1914 * Returns the idInSource for a given Synonym.
1917 private String
getIdInSource(TaxonBase taxonBase
) {
1918 String idInSource
= null;
1919 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1920 if (sources
.size() == 1) {
1921 IdentifiableSource source
= sources
.iterator().next();
1922 if (source
!= null) {
1923 idInSource
= source
.getIdInSource();
1925 } else if (sources
.size() > 1) {
1928 for (IdentifiableSource source
: sources
) {
1929 idInSource
+= source
.getIdInSource();
1930 if (count
< sources
.size()) {
1935 } else if (sources
.size() == 0){
1936 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
1945 * Returns the citation for a given Synonym.
1948 private Reference
getCitation(Synonym syn
) {
1949 Reference citation
= null;
1950 Set
<IdentifiableSource
> sources
= syn
.getSources();
1951 if (sources
.size() == 1) {
1952 IdentifiableSource source
= sources
.iterator().next();
1953 if (source
!= null) {
1954 citation
= source
.getCitation();
1956 } else if (sources
.size() > 1) {
1957 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1963 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1964 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1966 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1967 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1968 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1970 return inferredSynonyms
;