3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.cdm
.api
.service
;
13 import java
.io
.IOException
;
14 import java
.util
.ArrayList
;
15 import java
.util
.HashMap
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
19 import java
.util
.UUID
;
22 import org
.apache
.log4j
.Logger
;
23 import org
.apache
.lucene
.analysis
.Analyzer
;
24 import org
.apache
.lucene
.analysis
.standard
.StandardAnalyzer
;
25 import org
.apache
.lucene
.document
.Document
;
26 import org
.apache
.lucene
.document
.Field
;
27 import org
.apache
.lucene
.index
.CorruptIndexException
;
28 import org
.apache
.lucene
.index
.IndexReader
;
29 import org
.apache
.lucene
.queryParser
.ParseException
;
30 import org
.apache
.lucene
.queryParser
.QueryParser
;
31 import org
.apache
.lucene
.search
.HitCollector
;
32 import org
.apache
.lucene
.search
.IndexSearcher
;
33 import org
.apache
.lucene
.search
.Query
;
34 import org
.apache
.lucene
.search
.ScoreDoc
;
35 import org
.apache
.lucene
.search
.Searcher
;
36 import org
.apache
.lucene
.search
.TopDocCollector
;
37 import org
.apache
.lucene
.search
.TopDocs
;
38 import org
.hibernate
.search
.FullTextSession
;
39 import org
.hibernate
.search
.Search
;
40 import org
.hibernate
.search
.SearchFactory
;
41 import org
.hibernate
.search
.reader
.ReaderProvider
;
42 import org
.hibernate
.search
.store
.DirectoryProvider
;
43 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
44 import org
.springframework
.stereotype
.Service
;
45 import org
.springframework
.transaction
.annotation
.Propagation
;
46 import org
.springframework
.transaction
.annotation
.Transactional
;
48 import sun
.print
.resources
.serviceui
;
50 import eu
.etaxonomy
.cdm
.api
.service
.config
.ITaxonServiceConfigurator
;
51 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
52 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
53 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
54 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
55 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
56 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
57 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
58 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
59 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
60 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
61 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
62 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
63 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
64 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
65 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
66 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
67 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
68 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
69 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
70 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
71 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
72 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
73 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
74 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
75 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
76 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
77 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
78 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
79 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
80 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
81 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
82 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
83 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
84 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
85 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
86 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
87 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
88 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
89 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
90 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
91 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
92 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
93 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
94 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
95 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
96 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
97 import eu
.etaxonomy
.cdm
.search
.LuceneSearch
;
98 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
102 * @author a.kohlbecker
107 @Transactional(propagation
= Propagation
.SUPPORTS
, readOnly
= true)
108 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
109 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
112 private ITaxonNameDao nameDao
;
115 private ISearchResultBuilder searchResultBuilder
;
118 private IOrderedTermVocabularyDao orderedVocabularyDao
;
121 private INameService nameService
;
126 public TaxonServiceImpl(){
127 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
131 * FIXME Candidate for harmonization
132 * rename searchByName ?
134 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
135 return dao
.getTaxaByName(name
, sec
);
139 * FIXME Candidate for harmonization
140 * list(Synonym.class, ...)
142 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
144 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
145 return dao
.getAllSynonyms(limit
, start
);
149 * FIXME Candidate for harmonization
150 * list(Taxon.class, ...)
152 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
154 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
155 return dao
.getAllTaxa(limit
, start
);
159 * FIXME Candidate for harmonization
160 * merge with getRootTaxa(Reference sec, ..., ...)
162 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
164 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
165 if (cdmFetch
== null){
166 cdmFetch
= CdmFetch
.NO_FETCH();
168 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
173 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
175 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
176 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
180 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
182 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
183 return dao
.getAllRelationships(limit
, start
);
187 * FIXME Candidate for harmonization
188 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
191 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
193 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
194 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
195 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
196 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
197 return taxonRelTypeVocabulary
;
204 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
206 @Transactional(readOnly
= false)
207 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
209 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
210 synonymName
.removeTaxonBase(synonym
);
211 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
212 taxonName
.removeTaxonBase(acceptedTaxon
);
214 synonym
.setName(taxonName
);
215 acceptedTaxon
.setName(synonymName
);
217 // the accepted taxon needs a new uuid because the concept has changed
218 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
219 //acceptedTaxon.setUuid(UUID.randomUUID());
224 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
226 //TODO correct delete handling still needs to be implemented / checked
228 @Transactional(readOnly
= false)
229 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
231 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
232 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
233 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
235 //check synonym is not homotypic
236 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
237 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
238 throw new HomotypicalGroupChangeException(message
);
241 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
243 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
244 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
246 for (Synonym heteroSynonym
: heteroSynonyms
){
247 if (synonym
.equals(heteroSynonym
)){
248 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
250 //move synonyms in same homotypic group to new accepted taxon
251 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
255 //synonym.getName().removeTaxonBase(synonym);
256 //TODO correct delete handling still needs to be implemented / checked
258 // deleteSynonym(synonym, taxon, false);
261 this.delete(synonym
);
263 } catch (Exception e
) {
264 logger
.info("Can't delete old synonym from database");
268 return newAcceptedTaxon
;
272 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
274 // Get name from synonym
275 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
277 // remove synonym from taxon
278 toTaxon
.removeSynonym(synonym
);
280 // Create a taxon with synonym name
281 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
283 // Add taxon relation
284 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
286 // since we are swapping names, we have to detach the name from the synonym completely.
287 // Otherwise the synonym will still be in the list of typified names.
288 synonym
.getName().removeTaxonBase(synonym
);
295 * @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)
297 @Transactional(readOnly
= false)
299 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
300 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
302 TaxonNameBase synonymName
= synonym
.getName();
303 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
307 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
308 newHomotypicalGroup
.addTypifiedName(synonymName
);
310 //remove existing basionym relationships
311 synonymName
.removeBasionyms();
313 //add basionym relationship
314 if (setBasionymRelationIfApplicable
){
315 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
316 for (TaxonNameBase basionym
: basionyms
){
317 synonymName
.addBasionym(basionym
);
321 //set synonym relationship correctly
322 // SynonymRelationship relToTaxon = null;
323 boolean relToTargetTaxonExists
= false;
324 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
325 for (SynonymRelationship rel
: existingRelations
){
326 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
327 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
328 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
329 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
330 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
331 rel
.setType(newRelationType
);
332 //TODO handle citation and microCitation
335 relToTargetTaxonExists
= true;
337 if (removeFromOtherTaxa
){
338 acceptedTaxon
.removeSynonym(synonym
, false);
344 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
345 Taxon acceptedTaxon
= targetTaxon
;
346 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
347 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
348 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
349 //TODO handle citation and microCitation
350 Reference citation
= null;
351 String microCitation
= null;
352 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
359 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
362 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
364 clazz
= TaxonBase
.class;
366 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
370 protected void setDao(ITaxonDao dao
) {
375 * @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)
377 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
378 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
380 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
381 if(numberOfResults
> 0) { // no point checking again
382 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
385 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
389 * @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)
391 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
392 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
394 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
395 if(numberOfResults
> 0) { // no point checking again
396 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
403 * @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)
405 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
406 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
408 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
409 if(numberOfResults
> 0) { // no point checking again
410 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
416 * @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)
418 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
419 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
421 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
422 if(numberOfResults
> 0) { // no point checking again
423 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
425 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
429 * @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)
431 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
432 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
434 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
435 if(numberOfResults
> 0) { // no point checking again
436 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
442 * @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)
444 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
445 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
447 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
448 if(numberOfResults
> 0) { // no point checking again
449 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
451 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
455 * @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)
457 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
458 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
460 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
461 if(numberOfResults
> 0) { // no point checking again
462 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
465 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
469 * @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)
471 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
472 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
474 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
475 if(numberOfResults
> 0) { // no point checking again
476 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
479 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
483 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
485 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
486 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
487 return t
.getHomotypicSynonymsByHomotypicGroup();
491 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
493 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
494 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
495 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
496 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
497 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
498 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
500 return heterotypicSynonymyGroups
;
503 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(ITaxonServiceConfigurator configurator
){
505 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
506 // Class<? extends TaxonBase> clazz = null;
507 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
508 // clazz = TaxonBase.class;
509 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
510 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
511 // } else if(configurator.isDoTaxa()) {
512 // clazz = Taxon.class;
513 // //propertyPath = configurator.getTaxonPropertyPath();
514 // } else if (configurator.isDoSynonyms()) {
515 // clazz = Synonym.class;
516 // //propertyPath = configurator.getSynonymPropertyPath();
520 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
525 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
527 public Pager
<IdentifiableEntity
> findTaxaAndNames(ITaxonServiceConfigurator configurator
) {
529 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
530 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
531 List
<TaxonBase
> taxa
= null;
534 long numberTaxaResults
= 0L;
537 List
<String
> propertyPath
= new ArrayList
<String
>();
538 if(configurator
.getTaxonPropertyPath() != null){
539 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
543 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
544 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
546 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
547 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
548 configurator
.getNamedAreas());
551 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
552 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
553 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
554 configurator
.getMatchMode(), configurator
.getNamedAreas(),
555 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
559 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
562 results
.addAll(taxa
);
565 numberOfResults
+= numberTaxaResults
;
567 // Names without taxa
568 if (configurator
.isDoNamesWithoutTaxa()) {
569 int numberNameResults
= 0;
571 List
<?
extends TaxonNameBase
<?
,?
>> names
=
572 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
573 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
574 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
575 if (names
.size() > 0) {
576 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
577 if (taxonName
.getTaxonBases().size() == 0) {
578 results
.add(taxonName
);
582 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
583 numberOfResults
+= numberNameResults
;
587 // Taxa from common names
589 if (configurator
.isDoTaxaByCommonNames()) {
590 taxa
= new ArrayList
<TaxonBase
>();
591 numberTaxaResults
= 0;
592 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
593 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
595 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
596 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
597 for( Object
[] entry
: commonNameResults
) {
598 taxa
.add((TaxonBase
) entry
[0]);
602 results
.addAll(taxa
);
604 numberOfResults
+= numberTaxaResults
;
608 return new DefaultPagerImpl
<IdentifiableEntity
>
609 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
612 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
613 return dao
.getUuidAndTitleCache();
617 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
619 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
620 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
621 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
622 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
623 for (TaxonDescription taxDesc
: descriptions
){
624 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
625 for (DescriptionElementBase descElem
: elements
){
626 for(Media media
: descElem
.getMedia()){
628 //find the best matching representation
629 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
638 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
640 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
641 return this.dao
.findById(listOfIDs
);
645 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
647 public int countAllRelationships() {
648 return this.dao
.countAllRelationships();
655 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
657 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
658 return this.dao
.findIdenticalTaxonNames(propertyPath
);
663 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
665 @Transactional(readOnly
= false)
667 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
668 if (synonym
== null){
671 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
673 //remove synonymRelationship
674 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
678 taxonSet
.addAll(synonym
.getAcceptedTaxa());
680 for (Taxon relatedTaxon
: taxonSet
){
681 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
682 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
684 this.saveOrUpdate(synonym
);
686 //TODO remove name from homotypical group?
688 //remove synonym (if necessary)
689 if (synonym
.getSynonymRelations().isEmpty()){
690 TaxonNameBase
<?
,?
> name
= synonym
.getName();
691 synonym
.setName(null);
694 //remove name if possible (and required)
695 if (name
!= null && removeNameIfPossible
){
697 nameService
.delete(name
, new NameDeletionConfigurator());
698 }catch (DataChangeNoRollbackException ex
){
699 if (logger
.isDebugEnabled())logger
.debug("Name wasn't deleted as it is referenced");
707 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
709 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
711 return this.dao
.findIdenticalNamesNew(propertyPath
);
715 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
717 public String
getPhylumName(TaxonNameBase name
){
718 return this.dao
.getPhylumName(name
);
722 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
724 public long deleteSynonymRelationships(Synonym syn
) {
725 return dao
.deleteSynonymRelationships(syn
, null);
730 * @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)
732 public List
<SynonymRelationship
> listSynonymRelationships(
733 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
734 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
735 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
737 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
738 if(numberOfResults
> 0) { // no point checking again
739 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
745 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
748 public Taxon
findBestMatchingTaxon(String taxonName
) {
749 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
750 config
.setTaxonNameTitle(taxonName
);
751 return findBestMatchingTaxon(config
);
757 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
759 Taxon bestCandidate
= null;
761 // 1. search for acceptet taxa
762 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
763 boolean bestCandidateMatchesSecUuid
= false;
764 boolean bestCandidateIsInClassification
= false;
765 int countEqualCandidates
= 0;
766 for(TaxonBase taxonBaseCandidate
: taxonList
){
767 if(taxonBaseCandidate
instanceof Taxon
){
768 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
769 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
770 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
772 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
773 bestCandidate
= newCanditate
;
774 countEqualCandidates
= 1;
775 bestCandidateMatchesSecUuid
= true;
779 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
780 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
782 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
783 bestCandidate
= newCanditate
;
784 countEqualCandidates
= 1;
785 bestCandidateIsInClassification
= true;
788 if (bestCandidate
== null){
789 bestCandidate
= newCanditate
;
790 countEqualCandidates
= 1;
794 }else{ //not Taxon.class
797 countEqualCandidates
++;
800 if (bestCandidate
!= null){
801 if(countEqualCandidates
> 1){
802 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
803 return bestCandidate
;
805 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
806 return bestCandidate
;
811 // 2. search for synonyms
812 if (config
.isIncludeSynonyms()){
813 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
814 for(TaxonBase taxonBase
: synonymList
){
815 if(taxonBase
instanceof Synonym
){
816 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
817 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
818 if(!acceptetdCandidates
.isEmpty()){
819 bestCandidate
= acceptetdCandidates
.iterator().next();
820 if(acceptetdCandidates
.size() == 1){
821 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
822 return bestCandidate
;
824 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
825 return bestCandidate
;
827 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
833 } catch (Exception e
){
837 return bestCandidate
;
840 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
841 UUID configClassificationUuid
= config
.getClassificationUuid();
842 if (configClassificationUuid
== null){
845 for (TaxonNode node
: taxon
.getTaxonNodes()){
846 UUID classUuid
= node
.getClassification().getUuid();
847 if (configClassificationUuid
.equals(classUuid
)){
854 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
855 UUID configSecUuid
= config
.getSecUuid();
856 if (configSecUuid
== null){
859 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
860 return configSecUuid
.equals(taxonSecUuid
);
864 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
867 public Synonym
findBestMatchingSynonym(String taxonName
) {
868 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
869 if(! synonymList
.isEmpty()){
870 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
871 if(synonymList
.size() == 1){
872 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
875 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
884 * @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)
887 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
888 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
890 Synonym synonym
= oldSynonymRelation
.getSynonym();
891 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
892 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
893 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
894 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
895 //set default relationship type
896 if (newSynonymRelationshipType
== null){
897 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
899 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
901 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
902 int hgSize
= homotypicGroup
.getTypifiedNames().size();
903 boolean isSingleInGroup
= !(hgSize
> 1);
905 if (! isSingleInGroup
){
906 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
907 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
908 if (isHomotypicToAccepted
){
909 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.";
910 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
911 message
= String
.format(message
, homotypicRelatives
);
912 throw new HomotypicalGroupChangeException(message
);
914 if (! moveHomotypicGroup
){
915 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.";
916 throw new HomotypicalGroupChangeException(message
);
919 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
921 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
923 SynonymRelationship result
= null;
924 //move all synonyms to new taxon
925 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
926 for (Synonym syn
: homotypicSynonyms
){
927 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
928 for (SynonymRelationship synRelation
: synRelations
){
929 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
930 Reference
<?
> newReference
= reference
;
931 if (newReference
== null && keepReference
){
932 newReference
= synRelation
.getCitation();
934 String newRefDetail
= referenceDetail
;
935 if (newRefDetail
== null && keepReference
){
936 newRefDetail
= synRelation
.getCitationMicroReference();
938 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
939 fromTaxon
.removeSynonymRelation(synRelation
, false);
941 //change homotypic group of synonym if relType is 'homotypic'
942 // if (newRelTypeIsHomotypic){
943 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
946 if (synRelation
.equals(oldSynonymRelation
)){
947 result
= newSynRelation
;
953 saveOrUpdate(newTaxon
);
954 //Assert that there is a result
956 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
957 throw new IllegalStateException(message
);
963 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
966 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
967 return dao
.getUuidAndTitleCacheTaxon();
971 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
974 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
975 return dao
.getUuidAndTitleCacheSynonym();
979 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(Class
<?
extends DescriptionElementBase
> clazz
, String queryString
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
980 List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
982 String luceneQueryTemplate
= "titleCache:%1$s OR multilanguageText.text:%1$s OR name:%1$s";
983 String luceneQuery
= String
.format(luceneQueryTemplate
, queryString
);
985 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), clazz
);
986 TopDocs topDocsResultSet
= luceneSearch
.executeSearch(luceneQuery
);
987 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSetFromIds(luceneSearch
, topDocsResultSet
, dao
, "inDescription.taxon.id");
989 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, searchResults
.size(), pageSize
, searchResults
);
993 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
){
994 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
995 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
997 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1000 uuid
= taxon
.getName().getUuid();
1001 ZoologicalName taxonName
= getZoologicalName(uuid
, zooHashMap
);
1002 String epithetOfTaxon
= null;
1003 String infragenericEpithetOfTaxon
= null;
1004 String infraspecificEpithetOfTaxon
= null;
1005 if (taxonName
.isSpecies()){
1006 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1007 } else if (taxonName
.isInfraGeneric()){
1008 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1009 } else if (taxonName
.isInfraSpecific()){
1010 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1012 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1013 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1014 List
<String
> taxonNames
= new ArrayList
<String
>();
1016 for (TaxonNode node
: nodes
){
1017 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1018 // List<String> synonymsEpithet = new ArrayList<String>();
1020 if (node
.getClassification().equals(classification
)){
1021 if (!node
.isTopmostNode()){
1022 TaxonNode parent
= (TaxonNode
)node
.getParent();
1023 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1024 TaxonNameBase parentName
= parent
.getTaxon().getName();
1025 ZoologicalName zooParentName
= (ZoologicalName
)HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1026 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1027 Rank rankOfTaxon
= taxonName
.getRank();
1030 //create inferred synonyms for species, subspecies or subgenus
1031 if (parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())){
1033 Synonym inferredEpithet
;
1034 Synonym inferredGenus
= null;
1035 Synonym potentialCombination
;
1037 List
<String
> propertyPaths
= new ArrayList
<String
>();
1038 propertyPaths
.add("synonym");
1039 propertyPaths
.add("synonym.name");
1040 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1041 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1043 List
<SynonymRelationship
> synonymRelationshipsOfGenus
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1044 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1046 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1048 for (SynonymRelationship synonymRelationOfGenus
:synonymRelationshipsOfGenus
){
1049 TaxonNameBase synName
;
1050 ZoologicalName inferredSynName
;
1051 Synonym syn
= synonymRelationOfGenus
.getSynonym();
1052 HibernateProxyHelper
.deproxy(syn
);
1054 // Determine the idInSource
1055 String idInSource
= getIdInSource(syn
);
1057 // Determine the sourceReference
1058 Reference sourceReference
= syn
.getSec();
1060 synName
= syn
.getName();
1061 ZoologicalName zooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1062 String synGenusName
= zooName
.getGenusOrUninomial();
1063 String synInfraGenericEpithet
= null;
1064 String synSpecificEpithet
= null;
1065 if (zooName
.isInfraGeneric()){
1066 synInfraGenericEpithet
= zooName
.getInfraGenericEpithet();
1067 } else if (zooName
.isSpecies()){
1068 synSpecificEpithet
= zooName
.getSpecificEpithet();
1071 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1072 synonymsGenus.put(synGenusName, idInSource);
1075 inferredSynName
= ZoologicalName
.NewInstance(rankOfTaxon
);
1077 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
1078 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
1079 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
1081 inferredSynName
.setGenusOrUninomial(synGenusName
);
1082 if (inferredSynName
.isSpecies()){
1083 if (parentName
.isInfraGeneric()){
1084 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
1086 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1087 } else if (inferredSynName
.isInfraGeneric()) {
1088 inferredSynName
.setInfraGenericEpithet(infragenericEpithetOfTaxon
);
1089 } else if (inferredSynName
.isInfraSpecific()){
1090 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
1091 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
1094 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
1096 // Set the sourceReference
1097 inferredEpithet
.setSec(sourceReference
);
1099 // Add the original source
1100 if (idInSource
!= null) {
1101 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSource
, "InferredEpithetOf", syn
.getSec(), null);
1104 Reference citation
= getCitation(syn
);
1105 if (citation
!= null) {
1106 originalSource
.setCitation(citation
);
1107 inferredEpithet
.addSource(originalSource
);
1111 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_GENUS_OF());
1112 inferredSynonyms
.add(inferredEpithet
);
1113 inferredSynName
.generateTitle();
1114 zooHashMap
.put(inferredSynName
.getUuid(), inferredSynName
);
1115 taxonNames
.add(inferredSynName
.getNameCache());
1118 if (!taxonNames
.isEmpty()){
1119 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1120 ZoologicalName name
;
1121 if (!synNotInCDM
.isEmpty()){
1122 inferredSynonymsToBeRemoved
.clear();
1124 for (Synonym syn
:inferredSynonyms
){
1125 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1126 if (!synNotInCDM
.contains(name
.getNameCache())){
1127 inferredSynonymsToBeRemoved
.add(syn
);
1131 // Remove identified Synonyms from inferredSynonyms
1132 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1133 inferredSynonyms
.remove(synonym
);
1138 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1141 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1142 TaxonNameBase synName
;
1143 ZoologicalName inferredSynName
;
1145 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1146 synName
=syn
.getName();
1147 HibernateProxyHelper
.deproxy(syn
);
1149 // Determine the idInSource
1150 String idInSource
= getIdInSource(syn
);
1152 // Determine the sourceReference
1153 Reference sourceReference
= syn
.getSec();
1155 synName
= syn
.getName();
1156 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1157 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
1158 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
1159 synonymsEpithet.add(synSpeciesEpithetName);
1162 inferredSynName
= ZoologicalName
.NewInstance(rankOfTaxon
);
1163 //TODO:differ between parent is genusa 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...
1166 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
1168 if (taxonName
.isSpecies()){
1169 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
1170 if (zooParentName
.isInfraGeneric()){
1171 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
1174 if (taxonName
.isInfraSpecific()){
1175 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
1176 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
1178 if (taxonName
.isInfraGeneric()){
1179 inferredSynName
.setInfraGenericEpithet(synZooName
.getInfraGenericEpithet());
1182 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
1184 // Set the sourceReference
1185 inferredGenus
.setSec(sourceReference
);
1187 // Add the original source
1188 if (idInSource
!= null) {
1189 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSource
, "InferredGenusOf", syn
.getSec(), null);
1192 Reference citation
= getCitation(syn
);
1193 if (citation
!= null) {
1194 originalSource
.setCitation(citation
);
1195 inferredGenus
.addSource(originalSource
);
1199 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
1200 inferredSynonyms
.add(inferredGenus
);
1201 inferredSynName
.generateTitle();
1202 zooHashMap
.put(inferredSynName
.getUuid(), inferredSynName
);
1203 taxonNames
.add(inferredSynName
.getNameCache());
1206 if (!taxonNames
.isEmpty()){
1207 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1208 ZoologicalName name
;
1209 if (!synNotInCDM
.isEmpty()){
1210 inferredSynonymsToBeRemoved
.clear();
1212 for (Synonym syn
:inferredSynonyms
){
1213 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1214 if (!synNotInCDM
.contains(name
.getNameCache())){
1215 inferredSynonymsToBeRemoved
.add(syn
);
1219 // Remove identified Synonyms from inferredSynonyms
1220 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1221 inferredSynonyms
.remove(synonym
);
1226 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1228 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1229 ZoologicalName inferredSynName
;
1230 //for all synonyms of the parent...
1231 for (SynonymRelationship synonymRelationOfGenus
:synonymRelationshipsOfGenus
){
1232 TaxonNameBase synName
;
1233 Synonym synParent
= synonymRelationOfGenus
.getSynonym();
1234 synName
= synParent
.getName();
1236 HibernateProxyHelper
.deproxy(synParent
);
1238 // Set the sourceReference
1239 sourceReference
= synParent
.getSec();
1241 // Determine the idInSource
1242 String idInSourceParent
= getIdInSource(synParent
);
1244 ZoologicalName parentZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1245 String synParentGenus
= parentZooName
.getGenusOrUninomial();
1246 String synParentInfragenericName
= null;
1247 String synParentSpecificEpithet
= null;
1249 if (parentZooName
.isInfraGeneric()){
1250 synParentInfragenericName
= parentZooName
.getInfraGenericEpithet();
1252 if (parentZooName
.isSpecies()){
1253 synParentSpecificEpithet
= parentZooName
.getSpecificEpithet();
1256 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1257 synonymsGenus.put(synGenusName, idInSource);
1260 //for all synonyms of the taxon
1262 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1264 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1265 HibernateProxyHelper
.deproxy(syn
);
1267 // Set sourceReference
1268 sourceReference
= syn
.getSec();
1270 ZoologicalName zooName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1271 String synTaxonSpecificEpithet
= zooName
.getSpecificEpithet();
1272 String synTaxonInfragenericName
= null;
1273 String synTaxonInfraSpecificName
= null;
1275 if (parentZooName
.isSpecies()){
1276 synTaxonInfraSpecificName
= zooName
.getInfraSpecificEpithet();
1278 if (zooName
.isInfraGeneric()){
1279 synTaxonInfragenericName
= zooName
.getInfraGenericEpithet();
1282 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1283 synonymsEpithet.add(epithetName);
1286 //create potential combinations...
1287 inferredSynName
= ZoologicalName
.NewInstance(rankOfTaxon
);
1289 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1290 if (taxonName
.isSpecies()){
1291 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1292 if (parentName
.isInfraGeneric()){
1293 inferredSynName
.setInfraGenericEpithet(synTaxonInfragenericName
);
1296 if (taxonName
.isInfraSpecific()){
1297 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1298 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1300 if (taxonName
.isInfraGeneric()){
1301 inferredSynName
.setInfraGenericEpithet(synTaxonInfragenericName
);
1305 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1307 // Set the sourceReference
1308 potentialCombination
.setSec(sourceReference
);
1311 // Determine the idInSource
1312 String idInSourceTaxon
= getIdInSource(syn
);
1315 if (idInSourceTaxon
!= null) {
1316 IdentifiableSource originalSourceTaxon
= IdentifiableSource
.NewInstance(idInSourceTaxon
, "PotentialCombinationOf", sourceReference
, null);
1317 if (sourceReference
!= null) {
1318 originalSourceTaxon
.setCitation(sourceReference
);
1319 potentialCombination
.addSource(originalSourceTaxon
);
1322 if (idInSourceParent
!= null){
1323 IdentifiableSource originalSourceParent
= IdentifiableSource
.NewInstance(idInSourceParent
, "PotentialCombinationOf", sourceReference
, null);
1324 if (sourceReference
!= null) {
1325 originalSourceParent
.setCitation(sourceReference
);
1326 potentialCombination
.addSource(originalSourceParent
);
1334 inferredSynonyms
.add(potentialCombination
);
1335 inferredSynName
.generateTitle();
1336 zooHashMap
.put(inferredSynName
.getUuid(), inferredSynName
);
1337 taxonNames
.add(inferredSynName
.getNameCache());
1342 if (!taxonNames
.isEmpty()){
1343 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1344 ZoologicalName name
;
1345 if (!synNotInCDM
.isEmpty()){
1346 inferredSynonymsToBeRemoved
.clear();
1347 for (Synonym syn
:inferredSynonyms
){
1349 name
= (ZoologicalName
) syn
.getName();
1350 }catch (ClassCastException e
){
1351 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1353 if (!synNotInCDM
.contains(name
.getNameCache())){
1354 inferredSynonymsToBeRemoved
.add(syn
);
1357 // Remove identified Synonyms from inferredSynonyms
1358 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1359 inferredSynonyms
.remove(synonym
);
1365 logger
.info("The synonymrelationship type is not defined.");
1373 return inferredSynonyms
;
1377 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
1378 * Very likely only useful for createInferredSynonyms().
1383 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1384 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
1385 if (taxonName
== null) {
1386 taxonName
= zooHashMap
.get(uuid
);
1392 * Returns the idInSource for a given Synonym.
1395 private String
getIdInSource(Synonym syn
) {
1396 String idInSource
= null;
1397 Set
<IdentifiableSource
> sources
= syn
.getSources();
1398 if (sources
.size() == 1) {
1399 IdentifiableSource source
= sources
.iterator().next();
1400 if (source
!= null) {
1401 idInSource
= source
.getIdInSource();
1403 } else if (sources
.size() > 1) {
1406 for (IdentifiableSource source
: sources
) {
1407 idInSource
+= source
.getIdInSource();
1408 if (count
< sources
.size()) {
1420 * Returns the citation for a given Synonym.
1423 private Reference
getCitation(Synonym syn
) {
1424 Reference citation
= null;
1425 Set
<IdentifiableSource
> sources
= syn
.getSources();
1426 if (sources
.size() == 1) {
1427 IdentifiableSource source
= sources
.iterator().next();
1428 if (source
!= null) {
1429 citation
= source
.getCitation();
1431 } else if (sources
.size() > 1) {
1432 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
1438 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
){
1439 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1441 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF()));
1442 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF()));
1443 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF()));
1445 return inferredSynonyms
;