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
.Iterator
;
18 import java
.util
.List
;
21 import java
.util
.UUID
;
23 import org
.apache
.log4j
.Logger
;
24 import org
.apache
.lucene
.index
.CorruptIndexException
;
25 import org
.apache
.lucene
.queryParser
.ParseException
;
26 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
27 import org
.apache
.lucene
.search
.BooleanQuery
;
28 import org
.apache
.lucene
.search
.Query
;
29 import org
.apache
.lucene
.search
.SortField
;
30 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
31 import org
.springframework
.stereotype
.Service
;
32 import org
.springframework
.transaction
.annotation
.Transactional
;
34 import eu
.etaxonomy
.cdm
.api
.service
.config
.IFindTaxaAndNamesConfigurator
;
35 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
36 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
37 import eu
.etaxonomy
.cdm
.api
.service
.config
.SynonymDeletionConfigurator
;
38 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonBaseDeletionConfigurator
;
39 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
40 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonNodeDeletionConfigurator
.ChildHandling
;
41 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
42 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
43 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
44 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
45 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearch
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
49 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
.TopGroupsWithMaxScore
;
50 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
51 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
52 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
53 import eu
.etaxonomy
.cdm
.api
.service
.util
.TaxonRelationshipEdge
;
54 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
55 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
56 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
57 import eu
.etaxonomy
.cdm
.hibernate
.search
.GroupByTaxonClassBridge
;
58 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
59 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
60 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
61 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
62 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
63 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
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
.DescriptionBase
;
69 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
70 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
71 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
72 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
73 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
74 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
75 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
76 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
77 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
78 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
79 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
80 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
81 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
82 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
83 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
84 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
85 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
86 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
87 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
88 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
89 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
90 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
91 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
92 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
93 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
94 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
95 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
96 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
97 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
98 import eu
.etaxonomy
.cdm
.persistence
.dao
.AbstractBeanInitializer
;
99 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
100 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
101 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
102 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
103 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
104 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
105 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
106 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
107 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
108 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
112 * @author a.kohlbecker
117 @Transactional(readOnly
= true)
118 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
119 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
121 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
123 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
125 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
129 private ITaxonNameDao nameDao
;
132 private INameService nameService
;
135 private ICdmGenericDao genericDao
;
138 private IDescriptionService descriptionService
;
141 private IOrderedTermVocabularyDao orderedVocabularyDao
;
144 private IOccurrenceDao occurrenceDao
;
147 private AbstractBeanInitializer beanInitializer
;
152 public TaxonServiceImpl(){
153 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
157 * FIXME Candidate for harmonization
158 * rename searchByName ?
161 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
162 return dao
.getTaxaByName(name
, sec
);
166 * FIXME Candidate for harmonization
167 * list(Synonym.class, ...)
169 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
172 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
173 return dao
.getAllSynonyms(limit
, start
);
177 * FIXME Candidate for harmonization
178 * list(Taxon.class, ...)
180 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
183 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
184 return dao
.getAllTaxa(limit
, start
);
188 * FIXME Candidate for harmonization
189 * merge with getRootTaxa(Reference sec, ..., ...)
191 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
194 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
195 if (cdmFetch
== null){
196 cdmFetch
= CdmFetch
.NO_FETCH();
198 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
203 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
206 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
207 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
211 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
214 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
215 return dao
.getAllRelationships(limit
, start
);
219 * FIXME Candidate for harmonization
220 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
224 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
226 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
227 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
228 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
229 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
230 return taxonRelTypeVocabulary
;
237 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
240 @Transactional(readOnly
= false)
241 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
243 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
244 synonymName
.removeTaxonBase(synonym
);
245 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
246 taxonName
.removeTaxonBase(acceptedTaxon
);
248 synonym
.setName(taxonName
);
249 acceptedTaxon
.setName(synonymName
);
251 // the accepted taxon needs a new uuid because the concept has changed
252 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
253 //acceptedTaxon.setUuid(UUID.randomUUID());
258 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
260 //TODO correct delete handling still needs to be implemented / checked
262 @Transactional(readOnly
= false)
263 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
266 //TODO, check whether the synonym is related to the accepted taxon or not (see java doc)
267 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
268 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
269 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
271 //check synonym is not homotypic
272 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
273 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
274 throw new HomotypicalGroupChangeException(message
);
277 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
279 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
280 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
282 for (Synonym heteroSynonym
: heteroSynonyms
){
283 if (synonym
.equals(heteroSynonym
)){
284 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
286 //move synonyms in same homotypic group to new accepted taxon
287 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
291 //synonym.getName().removeTaxonBase(synonym);
292 //TODO correct delete handling still needs to be implemented / checked
294 // deleteSynonym(synonym, taxon, false);
297 this.deleteSynonym(synonym
, new SynonymDeletionConfigurator());
299 } catch (Exception e
) {
300 logger
.info("Can't delete old synonym from database");
304 return newAcceptedTaxon
;
309 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
311 // Get name from synonym
312 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
314 // remove synonym from taxon
315 toTaxon
.removeSynonym(synonym
);
317 // Create a taxon with synonym name
318 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
320 // Add taxon relation
321 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
323 // since we are swapping names, we have to detach the name from the synonym completely.
324 // Otherwise the synonym will still be in the list of typified names.
325 synonym
.getName().removeTaxonBase(synonym
);
332 * @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)
334 @Transactional(readOnly
= false)
336 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
337 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
339 TaxonNameBase synonymName
= synonym
.getName();
340 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
344 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
345 newHomotypicalGroup
.addTypifiedName(synonymName
);
347 //remove existing basionym relationships
348 synonymName
.removeBasionyms();
350 //add basionym relationship
351 if (setBasionymRelationIfApplicable
){
352 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
353 for (TaxonNameBase basionym
: basionyms
){
354 synonymName
.addBasionym(basionym
);
358 //set synonym relationship correctly
359 // SynonymRelationship relToTaxon = null;
360 boolean relToTargetTaxonExists
= false;
361 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
362 for (SynonymRelationship rel
: existingRelations
){
363 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
364 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
365 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
366 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
367 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
368 rel
.setType(newRelationType
);
369 //TODO handle citation and microCitation
372 relToTargetTaxonExists
= true;
374 if (removeFromOtherTaxa
){
375 acceptedTaxon
.removeSynonym(synonym
, false);
381 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
382 Taxon acceptedTaxon
= targetTaxon
;
383 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
384 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
385 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
386 //TODO handle citation and microCitation
387 Reference citation
= null;
388 String microCitation
= null;
389 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
396 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
399 @Transactional(readOnly
= false)
400 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
402 clazz
= TaxonBase
.class;
404 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
409 protected void setDao(ITaxonDao dao
) {
414 * @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)
417 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
418 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
420 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
421 if(numberOfResults
> 0) { // no point checking again
422 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
425 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
429 * @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)
432 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
433 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
435 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
436 if(numberOfResults
> 0) { // no point checking again
437 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
444 * @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)
447 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
448 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
450 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
451 if(numberOfResults
> 0) { // no point checking again
452 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
458 * @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)
461 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
462 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
464 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
465 if(numberOfResults
> 0) { // no point checking again
466 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
468 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
472 * @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)
475 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
476 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
478 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
479 if(numberOfResults
> 0) { // no point checking again
480 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
486 * @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)
489 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
490 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
492 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
493 if(numberOfResults
> 0) { // no point checking again
494 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
496 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
501 * @param includeRelationships
505 * @param propertyPaths
506 * @return an List which is not specifically ordered
509 public Set
<Taxon
> listRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Integer maxDepth
,
510 Integer limit
, Integer start
, List
<String
> propertyPaths
) {
512 Set
<Taxon
> relatedTaxa
= collectRelatedTaxa(taxon
, includeRelationships
, new HashSet
<Taxon
>(), maxDepth
);
513 relatedTaxa
.remove(taxon
);
514 beanInitializer
.initializeAll(relatedTaxa
, propertyPaths
);
520 * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the
521 * <code>taxon</code> supplied as parameter.
524 * @param includeRelationships
526 * @param maxDepth can be <code>null</code> for infinite depth
529 private Set
<Taxon
> collectRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Set
<Taxon
> taxa
, Integer maxDepth
) {
535 if(maxDepth
!= null) {
538 if(logger
.isDebugEnabled()){
539 logger
.debug("collecting related taxa for " + taxon
+ " with maxDepth=" + maxDepth
);
541 List
<TaxonRelationship
> taxonRelationships
= dao
.getTaxonRelationships(taxon
, null, null, null, null, null, null);
542 for (TaxonRelationship taxRel
: taxonRelationships
) {
545 if (taxRel
.getToTaxon() == null || taxRel
.getFromTaxon() == null || taxRel
.getType() == null) {
548 // filter by includeRelationships
549 for (TaxonRelationshipEdge relationshipEdgeFilter
: includeRelationships
) {
550 if ( relationshipEdgeFilter
.getTaxonRelationshipType().equals(taxRel
.getType()) ) {
551 if (relationshipEdgeFilter
.getDirections().contains(Direction
.relatedTo
) && !taxa
.contains(taxRel
.getToTaxon())) {
552 if(logger
.isDebugEnabled()){
553 logger
.debug(maxDepth
+ ": " + taxon
.getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxRel
.getToTaxon().getTitleCache());
555 taxa
.add(taxRel
.getToTaxon());
556 if(maxDepth
== null || maxDepth
> 0) {
557 taxa
.addAll(collectRelatedTaxa(taxRel
.getToTaxon(), includeRelationships
, taxa
, maxDepth
));
560 if(relationshipEdgeFilter
.getDirections().contains(Direction
.relatedFrom
) && !taxa
.contains(taxRel
.getFromTaxon())) {
561 taxa
.add(taxRel
.getFromTaxon());
562 if(logger
.isDebugEnabled()){
563 logger
.debug(maxDepth
+ ": " +taxRel
.getFromTaxon().getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxon
.getTitleCache() );
565 if(maxDepth
== null || maxDepth
> 0) {
566 taxa
.addAll(collectRelatedTaxa(taxRel
.getFromTaxon(), includeRelationships
, taxa
, maxDepth
));
576 * @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)
579 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
580 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
582 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
583 if(numberOfResults
> 0) { // no point checking again
584 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
587 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
591 * @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)
594 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
595 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
597 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
598 if(numberOfResults
> 0) { // no point checking again
599 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
602 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
606 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
609 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
610 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
611 return t
.getHomotypicSynonymsByHomotypicGroup();
615 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
618 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
619 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
620 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
621 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
622 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
623 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
625 return heterotypicSynonymyGroups
;
629 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
631 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
632 // Class<? extends TaxonBase> clazz = null;
633 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
634 // clazz = TaxonBase.class;
635 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
636 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
637 // } else if(configurator.isDoTaxa()) {
638 // clazz = Taxon.class;
639 // //propertyPath = configurator.getTaxonPropertyPath();
640 // } else if (configurator.isDoSynonyms()) {
641 // clazz = Synonym.class;
642 // //propertyPath = configurator.getSynonymPropertyPath();
646 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
651 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
654 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
656 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
657 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
658 List
<TaxonBase
> taxa
= null;
661 long numberTaxaResults
= 0L;
664 List
<String
> propertyPath
= new ArrayList
<String
>();
665 if(configurator
.getTaxonPropertyPath() != null){
666 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
670 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
671 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
673 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
674 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
675 configurator
.getNamedAreas());
678 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
679 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
680 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
681 configurator
.getMatchMode(), configurator
.getNamedAreas(),
682 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
686 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
689 results
.addAll(taxa
);
692 numberOfResults
+= numberTaxaResults
;
694 // Names without taxa
695 if (configurator
.isDoNamesWithoutTaxa()) {
696 int numberNameResults
= 0;
698 List
<?
extends TaxonNameBase
<?
,?
>> names
=
699 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
700 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
701 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
702 if (names
.size() > 0) {
703 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
704 if (taxonName
.getTaxonBases().size() == 0) {
705 results
.add(taxonName
);
709 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
710 numberOfResults
+= numberNameResults
;
714 // Taxa from common names
716 if (configurator
.isDoTaxaByCommonNames()) {
717 taxa
= new ArrayList
<TaxonBase
>();
718 numberTaxaResults
= 0;
719 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
720 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
722 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
723 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
724 for( Object
[] entry
: commonNameResults
) {
725 taxa
.add((TaxonBase
) entry
[0]);
729 results
.addAll(taxa
);
731 numberOfResults
+= numberTaxaResults
;
735 return new DefaultPagerImpl
<IdentifiableEntity
>
736 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
739 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
740 return dao
.getUuidAndTitleCache();
744 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
747 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
748 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
749 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
750 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
751 for (TaxonDescription taxDesc
: descriptions
){
752 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
753 for (DescriptionElementBase descElem
: elements
){
754 for(Media media
: descElem
.getMedia()){
756 //find the best matching representation
757 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
766 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
769 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, boolean limitToGalleries
, List
<String
> propertyPath
){
770 return listMedia(taxon
, includeRelationships
, limitToGalleries
, true, false, false, propertyPath
);
775 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)
778 public List
<Media
> listMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
779 Boolean limitToGalleries
, Boolean includeTaxonDescriptions
, Boolean includeOccurrences
,
780 Boolean includeTaxonNameDescriptions
, List
<String
> propertyPath
) {
782 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
783 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
785 if (limitToGalleries
== null) {
786 limitToGalleries
= false;
789 // --- resolve related taxa
790 if (includeRelationships
!= null) {
791 taxa
= listRelatedTaxa(taxon
, includeRelationships
, null, null, null, null);
794 taxa
.add((Taxon
) dao
.load(taxon
.getUuid()));
796 if(includeTaxonDescriptions
!= null && includeTaxonDescriptions
){
797 List
<TaxonDescription
> taxonDescriptions
= new ArrayList
<TaxonDescription
>();
798 // --- TaxonDescriptions
799 for (Taxon t
: taxa
) {
800 taxonDescriptions
.addAll(descriptionService
.listTaxonDescriptions(t
, null, null, null, null, propertyPath
));
802 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
803 if (!limitToGalleries
|| taxonDescription
.isImageGallery()) {
804 for (DescriptionElementBase element
: taxonDescription
.getElements()) {
805 for (Media media
: element
.getMedia()) {
806 taxonMedia
.add(media
);
813 if(includeOccurrences
!= null && includeOccurrences
) {
814 Set
<SpecimenOrObservationBase
> specimensOrObservations
= new HashSet
<SpecimenOrObservationBase
>();
816 for (Taxon t
: taxa
) {
817 specimensOrObservations
.addAll(occurrenceDao
.listByAssociatedTaxon(null, t
, null, null, null, null));
819 for (SpecimenOrObservationBase occurrence
: specimensOrObservations
) {
821 taxonMedia
.addAll(occurrence
.getMedia());
823 // SpecimenDescriptions
824 Set
<SpecimenDescription
> specimenDescriptions
= occurrence
.getSpecimenDescriptions();
825 for (DescriptionBase specimenDescription
: specimenDescriptions
) {
826 if (!limitToGalleries
|| specimenDescription
.isImageGallery()) {
827 Set
<DescriptionElementBase
> elements
= specimenDescription
.getElements();
828 for (DescriptionElementBase element
: elements
) {
829 for (Media media
: element
.getMedia()) {
830 taxonMedia
.add(media
);
837 if (occurrence
instanceof DerivedUnitBase
) {
838 if (((DerivedUnitBase
) occurrence
).getCollection() != null){
839 taxonMedia
.addAll(((DerivedUnitBase
) occurrence
).getCollection().getMedia());
844 if (occurrence
instanceof DnaSample
) {
845 Set
<Sequence
> sequences
= ((DnaSample
) occurrence
).getSequences();
846 for (Sequence sequence
: sequences
) {
847 taxonMedia
.addAll(sequence
.getChromatograms());
854 if(includeTaxonNameDescriptions
!= null && includeTaxonNameDescriptions
) {
855 // --- TaxonNameDescription
856 Set
<TaxonNameDescription
> nameDescriptions
= new HashSet
<TaxonNameDescription
>();
857 for (Taxon t
: taxa
) {
858 nameDescriptions
.addAll(t
.getName().getDescriptions());
860 for(TaxonNameDescription nameDescription
: nameDescriptions
){
861 if (!limitToGalleries
|| nameDescription
.isImageGallery()) {
862 Set
<DescriptionElementBase
> elements
= nameDescription
.getElements();
863 for (DescriptionElementBase element
: elements
) {
864 for (Media media
: element
.getMedia()) {
865 taxonMedia
.add(media
);
872 beanInitializer
.initializeAll(taxonMedia
, propertyPath
);
877 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
880 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
881 return this.dao
.listByIds(listOfIDs
, null, null, null, null);
885 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
888 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
889 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
893 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
896 public int countAllRelationships() {
897 return this.dao
.countAllRelationships();
904 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
907 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
908 return this.dao
.findIdenticalTaxonNames(propertyPath
);
913 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
916 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
, Classification classification
) throws ReferencedObjectUndeletableException
{
918 config
= new TaxonDeletionConfigurator();
922 if (! config
.isDeleteTaxonNodes()){
923 if (taxon
.getTaxonNodes().size() > 0){
924 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
925 throw new ReferencedObjectUndeletableException(message
);
928 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
929 Iterator
<TaxonNode
> iterator
= nodes
.iterator();
931 if (config
.isDeleteInAllClassifications()){
932 boolean deleteChildren
;
933 if (config
.getTaxonNodeConfig().getChildHandling().equals(ChildHandling
.DELETE
)){
934 deleteChildren
= true;
936 deleteChildren
= false;
939 taxon
.removeTaxonNodes(deleteChildren
);
941 while (iterator
.hasNext()){
942 node
= iterator
.next();
943 if (node
.getClassification().equals(classification
)){
954 // SynonymRelationShip
955 if (config
.isDeleteSynonymRelations()){
956 boolean removeSynonymNameFromHomotypicalGroup
= false;
957 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
958 Synonym synonym
= synRel
.getSynonym();
959 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
960 if (config
.isDeleteSynonymsIfPossible()){
962 boolean newHomotypicGroupIfNeeded
= true;
963 SynonymDeletionConfigurator synConfig
= new SynonymDeletionConfigurator();
965 deleteSynonym(synonym
, taxon
, synConfig
);
967 deleteSynonymRelationships(synonym
, taxon
);
973 if (! config
.isDeleteTaxonRelationships()){
974 if (taxon
.getTaxonRelations().size() > 0){
975 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.";
976 throw new ReferencedObjectUndeletableException(message
);
985 //check references with only reverse mapping
986 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
987 for (CdmBase referencingObject
: referencingObjects
){
988 //IIdentificationKeys (Media, Polytomous, MultiAccess)
989 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
990 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
991 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
992 throw new ReferencedObjectUndeletableException(message
);
997 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
998 String message
= "Taxon can't be deleted as it is used in polytomous key node";
999 throw new ReferencedObjectUndeletableException(message
);
1003 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
1004 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
1005 throw new ReferencedObjectUndeletableException(message
);
1011 if (config
.isDeleteNameIfPossible()){
1013 TaxonNameBase name
= nameService
.find(taxon
.getName().getUuid());
1014 name
.removeTaxonBase(taxon
);
1015 nameService
.save(name
);
1017 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
1018 } catch (ReferencedObjectUndeletableException e
) {
1020 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
1026 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
1028 for (TaxonDescription desc
: descriptions
){
1029 if (config
.isDeleteDescriptions()){
1030 //TODO use description delete configurator ?
1031 //FIXME check if description is ALWAYS deletable
1032 taxon
.removeDescription(desc
);
1033 descriptionService
.delete(desc
);
1035 if (desc
.getDescribedSpecimenOrObservations().size()>0){
1036 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
1037 " which also describes specimens or abservations";
1038 throw new ReferencedObjectUndeletableException(message
);
1048 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1050 @Transactional(readOnly
= false)
1052 public void deleteSynonym(Synonym synonym
, SynonymDeletionConfigurator config
) {
1053 deleteSynonym(synonym
, null, config
);
1059 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1061 @Transactional(readOnly
= false)
1063 public void deleteSynonym(Synonym synonym
, Taxon taxon
, SynonymDeletionConfigurator config
) {
1064 if (synonym
== null){
1067 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
1069 //remove synonymRelationship
1070 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
1072 taxonSet
.add(taxon
);
1074 taxonSet
.addAll(synonym
.getAcceptedTaxa());
1076 for (Taxon relatedTaxon
: taxonSet
){
1077 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
1078 relatedTaxon
.removeSynonym(synonym
, config
.isNewHomotypicGroupIfNeeded());
1080 this.saveOrUpdate(synonym
);
1082 //TODO remove name from homotypical group?
1084 //remove synonym (if necessary)
1087 if (synonym
.getSynonymRelations().isEmpty()){
1088 TaxonNameBase
<?
,?
> name
= synonym
.getName();
1089 synonym
.setName(null);
1090 dao
.delete(synonym
);
1092 //remove name if possible (and required)
1093 if (name
!= null && config
.isDeleteNameIfPossible()){
1095 nameService
.delete(name
, config
.getNameDeletionConfig());
1096 }catch (DataChangeNoRollbackException ex
){
1097 if (logger
.isDebugEnabled()) {
1098 logger
.debug("Name wasn't deleted as it is referenced");
1107 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
1110 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
1112 return this.dao
.findIdenticalNamesNew(propertyPath
);
1116 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1119 public String
getPhylumName(TaxonNameBase name
){
1120 return this.dao
.getPhylumName(name
);
1124 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
1127 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
1128 return dao
.deleteSynonymRelationships(syn
, taxon
);
1132 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
1135 public long deleteSynonymRelationships(Synonym syn
) {
1136 return dao
.deleteSynonymRelationships(syn
, null);
1141 * @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)
1144 public List
<SynonymRelationship
> listSynonymRelationships(
1145 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
1146 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
1147 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
1149 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
1150 if(numberOfResults
> 0) { // no point checking again
1151 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
1157 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
1160 public Taxon
findBestMatchingTaxon(String taxonName
) {
1161 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
1162 config
.setTaxonNameTitle(taxonName
);
1163 return findBestMatchingTaxon(config
);
1169 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
1171 Taxon bestCandidate
= null;
1173 // 1. search for acceptet taxa
1174 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1175 boolean bestCandidateMatchesSecUuid
= false;
1176 boolean bestCandidateIsInClassification
= false;
1177 int countEqualCandidates
= 0;
1178 for(TaxonBase taxonBaseCandidate
: taxonList
){
1179 if(taxonBaseCandidate
instanceof Taxon
){
1180 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
1181 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
1182 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
1184 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
1185 bestCandidate
= newCanditate
;
1186 countEqualCandidates
= 1;
1187 bestCandidateMatchesSecUuid
= true;
1191 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
1192 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
1194 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
1195 bestCandidate
= newCanditate
;
1196 countEqualCandidates
= 1;
1197 bestCandidateIsInClassification
= true;
1200 if (bestCandidate
== null){
1201 bestCandidate
= newCanditate
;
1202 countEqualCandidates
= 1;
1206 }else{ //not Taxon.class
1209 countEqualCandidates
++;
1212 if (bestCandidate
!= null){
1213 if(countEqualCandidates
> 1){
1214 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
1215 return bestCandidate
;
1217 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
1218 return bestCandidate
;
1223 // 2. search for synonyms
1224 if (config
.isIncludeSynonyms()){
1225 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1226 for(TaxonBase taxonBase
: synonymList
){
1227 if(taxonBase
instanceof Synonym
){
1228 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
1229 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
1230 if(!acceptetdCandidates
.isEmpty()){
1231 bestCandidate
= acceptetdCandidates
.iterator().next();
1232 if(acceptetdCandidates
.size() == 1){
1233 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
1234 return bestCandidate
;
1236 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
1237 return bestCandidate
;
1239 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
1245 } catch (Exception e
){
1249 return bestCandidate
;
1252 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
1253 UUID configClassificationUuid
= config
.getClassificationUuid();
1254 if (configClassificationUuid
== null){
1257 for (TaxonNode node
: taxon
.getTaxonNodes()){
1258 UUID classUuid
= node
.getClassification().getUuid();
1259 if (configClassificationUuid
.equals(classUuid
)){
1266 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1267 UUID configSecUuid
= config
.getSecUuid();
1268 if (configSecUuid
== null){
1271 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1272 return configSecUuid
.equals(taxonSecUuid
);
1276 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1279 public Synonym
findBestMatchingSynonym(String taxonName
) {
1280 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1281 if(! synonymList
.isEmpty()){
1282 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1283 if(synonymList
.size() == 1){
1284 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1287 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1296 * @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)
1299 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1300 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1302 Synonym synonym
= oldSynonymRelation
.getSynonym();
1303 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1304 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1305 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1306 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1307 //set default relationship type
1308 if (newSynonymRelationshipType
== null){
1309 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1311 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1313 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1314 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1315 boolean isSingleInGroup
= !(hgSize
> 1);
1317 if (! isSingleInGroup
){
1318 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1319 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1320 if (isHomotypicToAccepted
){
1321 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.";
1322 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1323 message
= String
.format(message
, homotypicRelatives
);
1324 throw new HomotypicalGroupChangeException(message
);
1326 if (! moveHomotypicGroup
){
1327 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.";
1328 throw new HomotypicalGroupChangeException(message
);
1331 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1333 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1335 SynonymRelationship result
= null;
1336 //move all synonyms to new taxon
1337 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1338 for (Synonym syn
: homotypicSynonyms
){
1339 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1340 for (SynonymRelationship synRelation
: synRelations
){
1341 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1342 Reference
<?
> newReference
= reference
;
1343 if (newReference
== null && keepReference
){
1344 newReference
= synRelation
.getCitation();
1346 String newRefDetail
= referenceDetail
;
1347 if (newRefDetail
== null && keepReference
){
1348 newRefDetail
= synRelation
.getCitationMicroReference();
1350 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1351 fromTaxon
.removeSynonymRelation(synRelation
, false);
1353 //change homotypic group of synonym if relType is 'homotypic'
1354 // if (newRelTypeIsHomotypic){
1355 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1358 if (synRelation
.equals(oldSynonymRelation
)){
1359 result
= newSynRelation
;
1365 saveOrUpdate(newTaxon
);
1366 //Assert that there is a result
1367 if (result
== null){
1368 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1369 throw new IllegalStateException(message
);
1375 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1378 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1379 return dao
.getUuidAndTitleCacheTaxon();
1383 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1386 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1387 return dao
.getUuidAndTitleCacheSynonym();
1391 * @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)
1394 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1395 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1396 Classification classification
, List
<Language
> languages
,
1397 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1400 LuceneSearch luceneSearch
= prepareFindByFullTextSearch(clazz
, queryString
, classification
, languages
, highlightFragments
);
1402 // --- execute search
1403 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1405 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1406 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1408 // --- initialize taxa, thighlight matches ....
1409 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1410 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1411 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1413 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupedHitCount
: 0;
1414 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1419 * @param queryString
1420 * @param classification
1422 * @param highlightFragments
1423 * @param directorySelectClass
1426 protected LuceneSearch
prepareFindByFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Language
> languages
,
1427 boolean highlightFragments
) {
1428 BooleanQuery finalQuery
= new BooleanQuery();
1429 BooleanQuery textQuery
= new BooleanQuery();
1431 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), TaxonBase
.class);
1432 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1434 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1435 luceneSearch
.setSortFields(sortFields
);
1437 // ---- search criteria
1438 luceneSearch
.setClazz(clazz
);
1440 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1441 textQuery
.add(queryFactory
.newDefinedTermQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1443 finalQuery
.add(textQuery
, Occur
.MUST
);
1445 if(classification
!= null){
1446 finalQuery
.add(queryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1448 luceneSearch
.setQuery(finalQuery
);
1450 if(highlightFragments
){
1451 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1453 return luceneSearch
;
1458 * @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)
1461 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1462 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1463 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1464 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1467 LuceneSearch luceneSearch
= prepareByDescriptionElementFullTextSearch(clazz
, queryString
, classification
, features
, languages
, highlightFragments
);
1469 // --- execute search
1470 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1472 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1473 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1475 // --- initialize taxa, highlight matches ....
1476 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1477 @SuppressWarnings("rawtypes")
1478 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1479 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1481 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1482 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1488 public Pager
<SearchResult
<TaxonBase
>> findByEverythingFullText(String queryString
,
1489 Classification classification
, List
<Language
> languages
, boolean highlightFragments
,
1490 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1492 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, null, languages
, highlightFragments
);
1493 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
);
1495 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
1497 // --- execute search
1498 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1500 // --- initialize taxa, highlight matches ....
1501 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1503 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1504 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1505 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1507 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1508 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1510 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupedHitCount
: 0;
1511 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1518 * @param queryString
1519 * @param classification
1522 * @param highlightFragments
1523 * @param directorySelectClass
1526 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Feature
> features
,
1527 List
<Language
> languages
, boolean highlightFragments
) {
1528 BooleanQuery finalQuery
= new BooleanQuery();
1529 BooleanQuery textQuery
= new BooleanQuery();
1531 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, DescriptionElementBase
.class);
1532 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1534 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", SortField
.STRING
, false)};
1535 luceneSearch
.setSortFields(sortFields
);
1537 // ---- search criteria
1538 luceneSearch
.setClazz(clazz
);
1539 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1543 if(languages
== null || languages
.size() == 0){
1544 nameQuery
= queryFactory
.newTermQuery("name", queryString
);
1546 nameQuery
= new BooleanQuery();
1547 BooleanQuery languageSubQuery
= new BooleanQuery();
1548 for(Language lang
: languages
){
1549 languageSubQuery
.add(queryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString(), false), Occur
.SHOULD
);
1551 ((BooleanQuery
) nameQuery
).add(queryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
1552 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1554 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1557 // text field from TextData
1558 textQuery
.add(queryFactory
.newMultilanguageTextQuery("text", queryString
, languages
), Occur
.SHOULD
);
1560 // --- TermBase fields - by representation ----
1561 // state field from CategoricalData
1562 textQuery
.add(queryFactory
.newDefinedTermQuery("states.state", queryString
, languages
), Occur
.SHOULD
);
1564 // state field from CategoricalData
1565 textQuery
.add(queryFactory
.newDefinedTermQuery("states.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1567 // area field from Distribution
1568 textQuery
.add(queryFactory
.newDefinedTermQuery("area", queryString
, languages
), Occur
.SHOULD
);
1570 // status field from Distribution
1571 textQuery
.add(queryFactory
.newDefinedTermQuery("status", queryString
, languages
), Occur
.SHOULD
);
1573 finalQuery
.add(textQuery
, Occur
.MUST
);
1574 // --- classification ----
1576 if(classification
!= null){
1577 finalQuery
.add(queryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
1580 // --- IdentifieableEntity fields - by uuid
1581 if(features
!= null && features
.size() > 0 ){
1582 finalQuery
.add(queryFactory
.newEntityUuidQuery("feature.uuid", features
), Occur
.MUST
);
1585 // the description must be associated with a taxon
1586 finalQuery
.add(queryFactory
.newIsNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
1588 logger
.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery
.toString());
1589 luceneSearch
.setQuery(finalQuery
);
1591 if(highlightFragments
){
1592 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1594 return luceneSearch
;
1598 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1599 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1600 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1602 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1603 * or {@link MultilanguageTextFieldBridge }
1604 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1605 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1606 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1608 * TODO move to utiliy class !!!!!!!!
1610 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1612 if(stringBuilder
== null){
1613 stringBuilder
= new StringBuilder();
1615 if(languages
== null || languages
.size() == 0){
1616 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
1618 for(Language lang
: languages
){
1619 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
1622 return stringBuilder
;
1626 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1627 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1628 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1630 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1633 UUID nameUuid
= taxon
.getName().getUuid();
1634 ZoologicalName taxonName
= getZoologicalName(nameUuid
, zooHashMap
);
1635 String epithetOfTaxon
= null;
1636 String infragenericEpithetOfTaxon
= null;
1637 String infraspecificEpithetOfTaxon
= null;
1638 if (taxonName
.isSpecies()){
1639 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1640 } else if (taxonName
.isInfraGeneric()){
1641 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1642 } else if (taxonName
.isInfraSpecific()){
1643 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1645 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1646 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1647 List
<String
> taxonNames
= new ArrayList
<String
>();
1649 for (TaxonNode node
: nodes
){
1650 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1651 // List<String> synonymsEpithet = new ArrayList<String>();
1653 if (node
.getClassification().equals(classification
)){
1654 if (!node
.isTopmostNode()){
1655 TaxonNode parent
= node
.getParent();
1656 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1657 TaxonNameBase
<?
,?
> parentName
= parent
.getTaxon().getName();
1658 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1659 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1660 Rank rankOfTaxon
= taxonName
.getRank();
1663 //create inferred synonyms for species, subspecies
1664 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1666 Synonym inferredEpithet
= null;
1667 Synonym inferredGenus
= null;
1668 Synonym potentialCombination
= null;
1670 List
<String
> propertyPaths
= new ArrayList
<String
>();
1671 propertyPaths
.add("synonym");
1672 propertyPaths
.add("synonym.name");
1673 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1674 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1676 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1677 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1679 List
<TaxonRelationship
> taxonRelListParent
= null;
1680 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1681 if (doWithMisappliedNames
){
1682 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1683 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1687 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1690 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1691 Synonym syn
= synonymRelationOfParent
.getSynonym();
1693 inferredEpithet
= createInferredEpithets(taxon
,
1694 zooHashMap
, taxonName
, epithetOfTaxon
,
1695 infragenericEpithetOfTaxon
,
1696 infraspecificEpithetOfTaxon
,
1697 taxonNames
, parentName
,
1701 inferredSynonyms
.add(inferredEpithet
);
1702 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1703 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1706 if (doWithMisappliedNames
){
1708 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1709 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1711 inferredEpithet
= createInferredEpithets(taxon
,
1712 zooHashMap
, taxonName
, epithetOfTaxon
,
1713 infragenericEpithetOfTaxon
,
1714 infraspecificEpithetOfTaxon
,
1715 taxonNames
, parentName
,
1718 inferredSynonyms
.add(inferredEpithet
);
1719 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1720 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1724 if (!taxonNames
.isEmpty()){
1725 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1726 ZoologicalName name
;
1727 if (!synNotInCDM
.isEmpty()){
1728 inferredSynonymsToBeRemoved
.clear();
1730 for (Synonym syn
:inferredSynonyms
){
1731 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1732 if (!synNotInCDM
.contains(name
.getNameCache())){
1733 inferredSynonymsToBeRemoved
.add(syn
);
1737 // Remove identified Synonyms from inferredSynonyms
1738 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1739 inferredSynonyms
.remove(synonym
);
1744 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1747 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1748 TaxonNameBase synName
;
1749 ZoologicalName inferredSynName
;
1751 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1752 inferredGenus
= createInferredGenus(taxon
,
1753 zooHashMap
, taxonName
, epithetOfTaxon
,
1754 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1756 inferredSynonyms
.add(inferredGenus
);
1757 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1758 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1763 if (doWithMisappliedNames
){
1765 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1766 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1767 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1769 inferredSynonyms
.add(inferredGenus
);
1770 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1771 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1776 if (!taxonNames
.isEmpty()){
1777 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1778 ZoologicalName name
;
1779 if (!synNotInCDM
.isEmpty()){
1780 inferredSynonymsToBeRemoved
.clear();
1782 for (Synonym syn
:inferredSynonyms
){
1783 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1784 if (!synNotInCDM
.contains(name
.getNameCache())){
1785 inferredSynonymsToBeRemoved
.add(syn
);
1789 // Remove identified Synonyms from inferredSynonyms
1790 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1791 inferredSynonyms
.remove(synonym
);
1796 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1798 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1799 ZoologicalName inferredSynName
;
1800 //for all synonyms of the parent...
1801 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1802 TaxonNameBase synName
;
1803 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1804 synName
= synParent
.getName();
1806 HibernateProxyHelper
.deproxy(synParent
);
1808 // Set the sourceReference
1809 sourceReference
= synParent
.getSec();
1811 // Determine the idInSource
1812 String idInSourceParent
= getIdInSource(synParent
);
1814 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1815 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1816 String synParentInfragenericName
= null;
1817 String synParentSpecificEpithet
= null;
1819 if (parentSynZooName
.isInfraGeneric()){
1820 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1822 if (parentSynZooName
.isSpecies()){
1823 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1826 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1827 synonymsGenus.put(synGenusName, idInSource);
1830 //for all synonyms of the taxon
1832 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1834 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1835 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1836 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1838 synParentInfragenericName
,
1839 synParentSpecificEpithet
, syn
, zooHashMap
);
1841 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1842 inferredSynonyms
.add(potentialCombination
);
1843 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1844 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1851 if (doWithMisappliedNames
){
1853 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1855 TaxonNameBase misappliedParentName
;
1857 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1858 misappliedParentName
= misappliedParent
.getName();
1860 HibernateProxyHelper
.deproxy(misappliedParent
);
1862 // Set the sourceReference
1863 sourceReference
= misappliedParent
.getSec();
1865 // Determine the idInSource
1866 String idInSourceParent
= getIdInSource(misappliedParent
);
1868 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1869 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1870 String synParentInfragenericName
= null;
1871 String synParentSpecificEpithet
= null;
1873 if (parentSynZooName
.isInfraGeneric()){
1874 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1876 if (parentSynZooName
.isSpecies()){
1877 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1881 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1882 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1883 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1884 potentialCombination
= createPotentialCombination(
1885 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1887 synParentInfragenericName
,
1888 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1891 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1892 inferredSynonyms
.add(potentialCombination
);
1893 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1894 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1899 if (!taxonNames
.isEmpty()){
1900 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1901 ZoologicalName name
;
1902 if (!synNotInCDM
.isEmpty()){
1903 inferredSynonymsToBeRemoved
.clear();
1904 for (Synonym syn
:inferredSynonyms
){
1906 name
= (ZoologicalName
) syn
.getName();
1907 }catch (ClassCastException e
){
1908 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1910 if (!synNotInCDM
.contains(name
.getNameCache())){
1911 inferredSynonymsToBeRemoved
.add(syn
);
1914 // Remove identified Synonyms from inferredSynonyms
1915 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1916 inferredSynonyms
.remove(synonym
);
1922 logger
.info("The synonymrelationship type is not defined.");
1923 return inferredSynonyms
;
1930 return inferredSynonyms
;
1933 private Synonym
createPotentialCombination(String idInSourceParent
,
1934 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1935 String synParentInfragenericName
, String synParentSpecificEpithet
,
1936 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1937 Synonym potentialCombination
;
1938 Reference sourceReference
;
1939 ZoologicalName inferredSynName
;
1940 HibernateProxyHelper
.deproxy(syn
);
1942 // Set sourceReference
1943 sourceReference
= syn
.getSec();
1944 if (sourceReference
== null){
1945 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1947 if (!parentSynZooName
.getTaxa().isEmpty()){
1948 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
1950 sourceReference
= taxon
.getSec();
1953 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1955 String synTaxonInfraSpecificName
= null;
1957 if (parentSynZooName
.isSpecies()){
1958 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1961 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1962 synonymsEpithet.add(epithetName);
1965 //create potential combinations...
1966 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1968 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1969 if (zooSynName
.isSpecies()){
1970 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1971 if (parentSynZooName
.isInfraGeneric()){
1972 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1975 if (zooSynName
.isInfraSpecific()){
1976 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1977 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1979 if (parentSynZooName
.isInfraGeneric()){
1980 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1984 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1986 // Set the sourceReference
1987 potentialCombination
.setSec(sourceReference
);
1990 // Determine the idInSource
1991 String idInSourceSyn
= getIdInSource(syn
);
1993 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1994 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1995 inferredSynName
.addSource(originalSource
);
1996 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1997 potentialCombination
.addSource(originalSource
);
2000 inferredSynName
.generateTitle();
2002 return potentialCombination
;
2005 private Synonym
createInferredGenus(Taxon taxon
,
2006 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2007 String epithetOfTaxon
, String genusOfTaxon
,
2008 List
<String
> taxonNames
, ZoologicalName zooParentName
,
2011 Synonym inferredGenus
;
2012 TaxonNameBase synName
;
2013 ZoologicalName inferredSynName
;
2014 synName
=syn
.getName();
2015 HibernateProxyHelper
.deproxy(syn
);
2017 // Determine the idInSource
2018 String idInSourceSyn
= getIdInSource(syn
);
2019 String idInSourceTaxon
= getIdInSource(taxon
);
2020 // Determine the sourceReference
2021 Reference sourceReference
= syn
.getSec();
2023 //logger.warn(sourceReference.getTitleCache());
2025 synName
= syn
.getName();
2026 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2027 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
2028 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
2029 synonymsEpithet.add(synSpeciesEpithetName);
2032 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2033 //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...
2036 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
2037 if (zooParentName
.isInfraGeneric()){
2038 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
2041 if (taxonName
.isSpecies()){
2042 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
2044 if (taxonName
.isInfraSpecific()){
2045 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2046 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
2050 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
2052 // Set the sourceReference
2053 inferredGenus
.setSec(sourceReference
);
2055 // Add the original source
2056 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
2057 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2058 inferredGenus
.addSource(originalSource
);
2060 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2061 inferredSynName
.addSource(originalSource
);
2062 originalSource
= null;
2065 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
2066 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2067 inferredGenus
.addSource(originalSource
);
2069 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2070 inferredSynName
.addSource(originalSource
);
2071 originalSource
= null;
2074 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
2076 inferredSynName
.generateTitle();
2079 return inferredGenus
;
2082 private Synonym
createInferredEpithets(Taxon taxon
,
2083 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2084 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
2085 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
2086 TaxonNameBase parentName
, TaxonBase syn
) {
2088 Synonym inferredEpithet
;
2089 TaxonNameBase
<?
,?
> synName
;
2090 ZoologicalName inferredSynName
;
2091 HibernateProxyHelper
.deproxy(syn
);
2093 // Determine the idInSource
2094 String idInSourceSyn
= getIdInSource(syn
);
2095 String idInSourceTaxon
= getIdInSource(taxon
);
2096 // Determine the sourceReference
2097 Reference
<?
> sourceReference
= syn
.getSec();
2099 if (sourceReference
== null){
2100 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2102 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
2103 sourceReference
= taxon
.getSec();
2106 synName
= syn
.getName();
2107 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2108 String synGenusName
= zooSynName
.getGenusOrUninomial();
2109 String synInfraGenericEpithet
= null;
2110 String synSpecificEpithet
= null;
2112 if (zooSynName
.getInfraGenericEpithet() != null){
2113 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
2116 if (zooSynName
.isInfraSpecific()){
2117 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
2120 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2121 synonymsGenus.put(synGenusName, idInSource);
2124 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2126 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
2127 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
2128 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
2130 inferredSynName
.setGenusOrUninomial(synGenusName
);
2132 if (parentName
.isInfraGeneric()){
2133 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
2135 if (taxonName
.isSpecies()){
2136 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2137 }else if (taxonName
.isInfraSpecific()){
2138 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
2139 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
2142 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
2144 // Set the sourceReference
2145 inferredEpithet
.setSec(sourceReference
);
2147 /* Add the original source
2148 if (idInSource != null) {
2149 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
2152 Reference citation = getCitation(syn);
2153 if (citation != null) {
2154 originalSource.setCitation(citation);
2155 inferredEpithet.addSource(originalSource);
2158 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
2161 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2163 inferredEpithet
.addSource(originalSource
);
2165 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2167 inferredSynName
.addSource(originalSource
);
2171 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
2173 inferredSynName
.generateTitle();
2174 return inferredEpithet
;
2178 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
2179 * Very likely only useful for createInferredSynonyms().
2184 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2185 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
2186 if (taxonName
== null) {
2187 taxonName
= zooHashMap
.get(uuid
);
2193 * Returns the idInSource for a given Synonym.
2196 private String
getIdInSource(TaxonBase taxonBase
) {
2197 String idInSource
= null;
2198 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
2199 if (sources
.size() == 1) {
2200 IdentifiableSource source
= sources
.iterator().next();
2201 if (source
!= null) {
2202 idInSource
= source
.getIdInSource();
2204 } else if (sources
.size() > 1) {
2207 for (IdentifiableSource source
: sources
) {
2208 idInSource
+= source
.getIdInSource();
2209 if (count
< sources
.size()) {
2214 } else if (sources
.size() == 0){
2215 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
2224 * Returns the citation for a given Synonym.
2227 private Reference
getCitation(Synonym syn
) {
2228 Reference citation
= null;
2229 Set
<IdentifiableSource
> sources
= syn
.getSources();
2230 if (sources
.size() == 1) {
2231 IdentifiableSource source
= sources
.iterator().next();
2232 if (source
!= null) {
2233 citation
= source
.getCitation();
2235 } else if (sources
.size() > 1) {
2236 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
2243 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
2244 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2246 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
2247 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
2248 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
2250 return inferredSynonyms
;
2254 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listClassifications(eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)
2257 public List
<Classification
> listClassifications(TaxonBase taxonBase
, Integer limit
, Integer start
, List
<String
> propertyPaths
) {
2259 // TODO quickly implemented, create according dao !!!!
2260 Set
<TaxonNode
> nodes
= new HashSet
<TaxonNode
>();
2261 Set
<Classification
> classifications
= new HashSet
<Classification
>();
2262 List
<Classification
> list
= new ArrayList
<Classification
>();
2264 if (taxonBase
== null) {
2268 taxonBase
= load(taxonBase
.getUuid());
2270 if (taxonBase
instanceof Taxon
) {
2271 nodes
.addAll(((Taxon
)taxonBase
).getTaxonNodes());
2273 for (Taxon taxon
: ((Synonym
)taxonBase
).getAcceptedTaxa() ) {
2274 nodes
.addAll(taxon
.getTaxonNodes());
2277 for (TaxonNode node
: nodes
) {
2278 classifications
.add(node
.getClassification());
2280 list
.addAll(classifications
);