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
<Language
> languages
, boolean highlightFragments
,
1224 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1226 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, null, languages
, highlightFragments
);
1227 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
);
1229 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
1231 // --- execute search
1232 TopDocs topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1234 // --- initialize taxa, thighlight matches ....
1235 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1236 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1237 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, "inDescription.taxon.id", propertyPaths
);
1239 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, topDocsResultSet
.totalHits
, pageSize
, searchResults
);
1246 * @param queryString
1247 * @param classification
1250 * @param highlightFragments
1251 * @param directorySelectClass
1254 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Feature
> features
,
1255 List
<Language
> languages
, boolean highlightFragments
) {
1256 BooleanQuery finalQuery
= new BooleanQuery();
1257 BooleanQuery textQuery
= new BooleanQuery();
1259 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), DescriptionElementBase
.class);
1260 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1262 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", false)};
1263 luceneSearch
.setSortFields(sortFields
);
1265 // ---- search criteria
1266 luceneSearch
.setClazz(clazz
);
1267 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1271 if(languages
== null || languages
.size() == 0){
1272 nameQuery
= queryFactory
.newTermQuery("name", queryString
);
1274 nameQuery
= new BooleanQuery();
1275 BooleanQuery languageSubQuery
= new BooleanQuery();
1276 for(Language lang
: languages
){
1277 languageSubQuery
.add(queryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString()), Occur
.SHOULD
);
1279 ((BooleanQuery
) nameQuery
).add(queryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
1280 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1282 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1285 // text field from TextData
1286 textQuery
.add(queryFactory
.newLocalizedTermQuery("text", queryString
, languages
), Occur
.SHOULD
);
1288 // --- TermBase fields - by representation ----
1289 // state field from CategoricalData
1290 textQuery
.add(queryFactory
.newLocalizedTermQuery("states.state.representation", queryString
, languages
), Occur
.SHOULD
);
1292 // state field from CategoricalData
1293 textQuery
.add(queryFactory
.newLocalizedTermQuery("states.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1295 finalQuery
.add(textQuery
, Occur
.MUST
);
1296 // --- classification ----
1298 if(classification
!= null){
1299 finalQuery
.add(queryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
1302 // --- IdentifieableEntity fields - by uuid
1303 if(features
!= null && features
.size() > 0 ){
1304 finalQuery
.add(queryFactory
.newEntityUuidQuery("feature.uuid", features
), Occur
.MUST
);
1307 // the description must be associated with a taxon
1308 finalQuery
.add(queryFactory
.newIsNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
1310 luceneSearch
.setQuery(finalQuery
);
1312 if(highlightFragments
){
1313 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1315 return luceneSearch
;
1319 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1320 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1321 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1323 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1324 * or {@link MultilanguageTextFieldBridge }
1325 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1326 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1327 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1329 * TODO move to utiliy class !!!!!!!!
1331 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1333 if(stringBuilder
== null){
1334 stringBuilder
= new StringBuilder();
1336 if(languages
== null || languages
.size() == 0){
1337 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
1339 for(Language lang
: languages
){
1340 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
1343 return stringBuilder
;
1346 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1347 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1348 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1350 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1353 UUID uuid
= taxon
.getName().getUuid();
1354 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1355 String epithetOfTaxon
= null;
1356 String infragenericEpithetOfTaxon
= null;
1357 String infraspecificEpithetOfTaxon
= null;
1358 if (taxonName
.isSpecies()){
1359 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1360 } else if (taxonName
.isInfraGeneric()){
1361 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1362 } else if (taxonName
.isInfraSpecific()){
1363 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1365 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1366 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1367 List
<String
> taxonNames
= new ArrayList
<String
>();
1369 for (TaxonNode node
: nodes
){
1370 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1371 // List<String> synonymsEpithet = new ArrayList<String>();
1373 if (node
.getClassification().equals(classification
)){
1374 if (!node
.isTopmostNode()){
1375 TaxonNode parent
= (TaxonNode
)node
.getParent();
1376 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1377 TaxonNameBase parentName
= parent
.getTaxon().getName();
1378 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1379 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1380 Rank rankOfTaxon
= taxonName
.getRank();
1383 //create inferred synonyms for species, subspecies
1384 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1386 Synonym inferredEpithet
= null;
1387 Synonym inferredGenus
= null;
1388 Synonym potentialCombination
= null;
1390 List
<String
> propertyPaths
= new ArrayList
<String
>();
1391 propertyPaths
.add("synonym");
1392 propertyPaths
.add("synonym.name");
1393 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1394 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1396 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1397 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1399 List
<TaxonRelationship
> taxonRelListParent
= null;
1400 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1401 if (doWithMisappliedNames
){
1402 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1403 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1407 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1408 Set
<String
> genusNames
= new HashSet
<String
>();
1410 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1411 Synonym syn
= synonymRelationOfParent
.getSynonym();
1413 inferredEpithet
= createInferredEpithets(taxon
,
1414 zooHashMap
, taxonName
, epithetOfTaxon
,
1415 infragenericEpithetOfTaxon
,
1416 infraspecificEpithetOfTaxon
,
1417 taxonNames
, parentName
,
1421 inferredSynonyms
.add(inferredEpithet
);
1422 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1423 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1426 if (doWithMisappliedNames
){
1428 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1429 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1431 inferredEpithet
= createInferredEpithets(taxon
,
1432 zooHashMap
, taxonName
, epithetOfTaxon
,
1433 infragenericEpithetOfTaxon
,
1434 infraspecificEpithetOfTaxon
,
1435 taxonNames
, parentName
,
1438 inferredSynonyms
.add(inferredEpithet
);
1439 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1440 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1444 if (!taxonNames
.isEmpty()){
1445 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1446 ZoologicalName name
;
1447 if (!synNotInCDM
.isEmpty()){
1448 inferredSynonymsToBeRemoved
.clear();
1450 for (Synonym syn
:inferredSynonyms
){
1451 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1452 if (!synNotInCDM
.contains(name
.getNameCache())){
1453 inferredSynonymsToBeRemoved
.add(syn
);
1457 // Remove identified Synonyms from inferredSynonyms
1458 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1459 inferredSynonyms
.remove(synonym
);
1464 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1467 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1468 TaxonNameBase synName
;
1469 ZoologicalName inferredSynName
;
1471 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1472 inferredGenus
= createInferredGenus(taxon
,
1473 zooHashMap
, taxonName
, epithetOfTaxon
,
1474 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1476 inferredSynonyms
.add(inferredGenus
);
1477 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1478 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1483 if (doWithMisappliedNames
){
1485 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1486 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1487 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1489 inferredSynonyms
.add(inferredGenus
);
1490 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1491 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1496 if (!taxonNames
.isEmpty()){
1497 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1498 ZoologicalName name
;
1499 if (!synNotInCDM
.isEmpty()){
1500 inferredSynonymsToBeRemoved
.clear();
1502 for (Synonym syn
:inferredSynonyms
){
1503 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1504 if (!synNotInCDM
.contains(name
.getNameCache())){
1505 inferredSynonymsToBeRemoved
.add(syn
);
1509 // Remove identified Synonyms from inferredSynonyms
1510 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1511 inferredSynonyms
.remove(synonym
);
1516 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1518 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1519 ZoologicalName inferredSynName
;
1520 //for all synonyms of the parent...
1521 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1522 TaxonNameBase synName
;
1523 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1524 synName
= synParent
.getName();
1526 HibernateProxyHelper
.deproxy(synParent
);
1528 // Set the sourceReference
1529 sourceReference
= synParent
.getSec();
1531 // Determine the idInSource
1532 String idInSourceParent
= getIdInSource(synParent
);
1534 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1535 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1536 String synParentInfragenericName
= null;
1537 String synParentSpecificEpithet
= null;
1539 if (parentSynZooName
.isInfraGeneric()){
1540 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1542 if (parentSynZooName
.isSpecies()){
1543 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1546 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1547 synonymsGenus.put(synGenusName, idInSource);
1550 //for all synonyms of the taxon
1552 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1554 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1555 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1556 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1558 synParentInfragenericName
,
1559 synParentSpecificEpithet
, syn
, zooHashMap
);
1561 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1562 inferredSynonyms
.add(potentialCombination
);
1563 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1564 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1571 if (doWithMisappliedNames
){
1573 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1575 TaxonNameBase misappliedParentName
;
1577 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1578 misappliedParentName
= misappliedParent
.getName();
1580 HibernateProxyHelper
.deproxy(misappliedParent
);
1582 // Set the sourceReference
1583 sourceReference
= misappliedParent
.getSec();
1585 // Determine the idInSource
1586 String idInSourceParent
= getIdInSource(misappliedParent
);
1588 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1589 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1590 String synParentInfragenericName
= null;
1591 String synParentSpecificEpithet
= null;
1593 if (parentSynZooName
.isInfraGeneric()){
1594 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1596 if (parentSynZooName
.isSpecies()){
1597 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1601 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1602 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1603 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1604 potentialCombination
= createPotentialCombination(
1605 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1607 synParentInfragenericName
,
1608 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1611 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1612 inferredSynonyms
.add(potentialCombination
);
1613 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1614 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1619 if (!taxonNames
.isEmpty()){
1620 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1621 ZoologicalName name
;
1622 if (!synNotInCDM
.isEmpty()){
1623 inferredSynonymsToBeRemoved
.clear();
1624 for (Synonym syn
:inferredSynonyms
){
1626 name
= (ZoologicalName
) syn
.getName();
1627 }catch (ClassCastException e
){
1628 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1630 if (!synNotInCDM
.contains(name
.getNameCache())){
1631 inferredSynonymsToBeRemoved
.add(syn
);
1634 // Remove identified Synonyms from inferredSynonyms
1635 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1636 inferredSynonyms
.remove(synonym
);
1642 logger
.info("The synonymrelationship type is not defined.");
1643 return inferredSynonyms
;
1650 return inferredSynonyms
;
1653 private Synonym
createPotentialCombination(String idInSourceParent
,
1654 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1655 String synParentInfragenericName
, String synParentSpecificEpithet
,
1656 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1657 Synonym potentialCombination
;
1658 Reference sourceReference
;
1659 ZoologicalName inferredSynName
;
1660 HibernateProxyHelper
.deproxy(syn
);
1662 // Set sourceReference
1663 sourceReference
= syn
.getSec();
1664 if (sourceReference
== null){
1665 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1667 if (!parentSynZooName
.getTaxa().isEmpty()){
1668 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
1670 sourceReference
= taxon
.getSec();
1673 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1675 String synTaxonInfraSpecificName
= null;
1677 if (parentSynZooName
.isSpecies()){
1678 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1681 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1682 synonymsEpithet.add(epithetName);
1685 //create potential combinations...
1686 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1688 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1689 if (zooSynName
.isSpecies()){
1690 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1691 if (parentSynZooName
.isInfraGeneric()){
1692 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1695 if (zooSynName
.isInfraSpecific()){
1696 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1697 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1699 if (parentSynZooName
.isInfraGeneric()){
1700 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1704 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1706 // Set the sourceReference
1707 potentialCombination
.setSec(sourceReference
);
1710 // Determine the idInSource
1711 String idInSourceSyn
= getIdInSource(syn
);
1713 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1714 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1715 inferredSynName
.addSource(originalSource
);
1716 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1717 potentialCombination
.addSource(originalSource
);
1720 inferredSynName
.generateTitle();
1722 return potentialCombination
;
1725 private Synonym
createInferredGenus(Taxon taxon
,
1726 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1727 String epithetOfTaxon
, String genusOfTaxon
,
1728 List
<String
> taxonNames
, ZoologicalName zooParentName
,
1731 Synonym inferredGenus
;
1732 TaxonNameBase synName
;
1733 ZoologicalName inferredSynName
;
1734 synName
=syn
.getName();
1735 HibernateProxyHelper
.deproxy(syn
);
1737 // Determine the idInSource
1738 String idInSourceSyn
= getIdInSource(syn
);
1739 String idInSourceTaxon
= getIdInSource(taxon
);
1740 // Determine the sourceReference
1741 Reference sourceReference
= syn
.getSec();
1743 //logger.warn(sourceReference.getTitleCache());
1745 synName
= syn
.getName();
1746 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1747 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1748 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1749 synonymsEpithet.add(synSpeciesEpithetName);
1752 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1753 //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...
1756 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1757 if (zooParentName
.isInfraGeneric()){
1758 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1761 if (taxonName
.isSpecies()){
1762 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1764 if (taxonName
.isInfraSpecific()){
1765 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1766 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1770 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1772 // Set the sourceReference
1773 inferredGenus
.setSec(sourceReference
);
1775 // Add the original source
1776 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
1777 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1778 inferredGenus
.addSource(originalSource
);
1780 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1781 inferredSynName
.addSource(originalSource
);
1782 originalSource
= null;
1785 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
1786 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1787 inferredGenus
.addSource(originalSource
);
1789 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
1790 inferredSynName
.addSource(originalSource
);
1791 originalSource
= null;
1794 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1796 inferredSynName
.generateTitle();
1799 return inferredGenus
;
1802 private Synonym
createInferredEpithets(Taxon taxon
,
1803 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1804 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
1805 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
1806 TaxonNameBase parentName
, TaxonBase syn
) {
1808 Synonym inferredEpithet
;
1809 TaxonNameBase synName
;
1810 ZoologicalName inferredSynName
;
1811 HibernateProxyHelper
.deproxy(syn
);
1813 // Determine the idInSource
1814 String idInSourceSyn
= getIdInSource(syn
);
1815 String idInSourceTaxon
= getIdInSource(taxon
);
1816 // Determine the sourceReference
1817 Reference sourceReference
= syn
.getSec();
1819 if (sourceReference
== null){
1820 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1822 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
1823 sourceReference
= taxon
.getSec();
1826 synName
= syn
.getName();
1827 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1828 String synGenusName
= zooSynName
.getGenusOrUninomial();
1829 String synInfraGenericEpithet
= null;
1830 String synSpecificEpithet
= null;
1832 if (zooSynName
.getInfraGenericEpithet() != null){
1833 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
1836 if (zooSynName
.isInfraSpecific()){
1837 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
1840 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1841 synonymsGenus.put(synGenusName, idInSource);
1844 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
1846 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1847 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1848 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1850 inferredSynName
.setGenusOrUninomial(synGenusName
);
1852 if (parentName
.isInfraGeneric()){
1853 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1855 if (taxonName
.isSpecies()){
1856 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1857 }else if (taxonName
.isInfraSpecific()){
1858 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1859 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1862 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1864 // Set the sourceReference
1865 inferredEpithet
.setSec(sourceReference
);
1867 /* Add the original source
1868 if (idInSource != null) {
1869 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
1872 Reference citation = getCitation(syn);
1873 if (citation != null) {
1874 originalSource.setCitation(citation);
1875 inferredEpithet.addSource(originalSource);
1878 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
1880 IdentifiableSource originalSource
;
1881 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1883 inferredEpithet
.addSource(originalSource
);
1885 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
1887 inferredSynName
.addSource(originalSource
);
1891 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1893 inferredSynName
.generateTitle();
1894 return inferredEpithet
;
1898 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1899 * Very likely only useful for createInferredSynonyms().
1904 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1905 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1906 if (taxonName
== null) {
1907 taxonName
= zooHashMap
.get(uuid
);
1913 * Returns the idInSource for a given Synonym.
1916 private String
getIdInSource(TaxonBase taxonBase
) {
1917 String idInSource
= null;
1918 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
1919 if (sources
.size() == 1) {
1920 IdentifiableSource source
= sources
.iterator().next();
1921 if (source
!= null) {
1922 idInSource
= source
.getIdInSource();
1924 } else if (sources
.size() > 1) {
1927 for (IdentifiableSource source
: sources
) {
1928 idInSource
+= source
.getIdInSource();
1929 if (count
< sources
.size()) {
1934 } else if (sources
.size() == 0){
1935 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
1944 * Returns the citation for a given Synonym.
1947 private Reference
getCitation(Synonym syn
) {
1948 Reference citation
= null;
1949 Set
<IdentifiableSource
> sources
= syn
.getSources();
1950 if (sources
.size() == 1) {
1951 IdentifiableSource source
= sources
.iterator().next();
1952 if (source
!= null) {
1953 citation
= source
.getCitation();
1955 } else if (sources
.size() > 1) {
1956 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1962 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
1963 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1965 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
1966 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
1967 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
1969 return inferredSynonyms
;