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
.EnumSet
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
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
.BooleanFilter
;
28 import org
.apache
.lucene
.search
.BooleanQuery
;
29 import org
.apache
.lucene
.search
.Query
;
30 import org
.apache
.lucene
.search
.QueryWrapperFilter
;
31 import org
.apache
.lucene
.search
.SortField
;
32 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
33 import org
.springframework
.stereotype
.Service
;
34 import org
.springframework
.transaction
.annotation
.Transactional
;
36 import eu
.etaxonomy
.cdm
.api
.service
.config
.IFindTaxaAndNamesConfigurator
;
37 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
38 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
39 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
40 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
41 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
42 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
43 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
44 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
45 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
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
.LuceneMultiSearchException
;
49 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
50 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
.TopGroupsWithMaxScore
;
51 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
52 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
53 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
54 import eu
.etaxonomy
.cdm
.api
.service
.util
.TaxonRelationshipEdge
;
55 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
56 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
57 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
58 import eu
.etaxonomy
.cdm
.hibernate
.search
.GroupByTaxonClassBridge
;
59 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
60 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
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
.Language
;
65 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
66 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
67 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
68 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
69 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
70 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
71 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
72 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
73 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
74 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
75 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
76 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTermBase
;
77 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
78 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
79 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
80 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
81 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
82 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
83 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
84 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
85 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
86 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
87 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
88 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
89 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
90 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
91 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
92 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
93 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
94 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
95 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
96 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
97 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
98 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
99 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
100 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
101 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
102 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
103 import eu
.etaxonomy
.cdm
.persistence
.dao
.AbstractBeanInitializer
;
104 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
105 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
106 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
107 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
108 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
109 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
110 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
111 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
112 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
113 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
117 * @author a.kohlbecker
122 @Transactional(readOnly
= true)
123 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
124 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
126 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
128 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
130 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
134 private ITaxonNameDao nameDao
;
137 private INameService nameService
;
140 private ICdmGenericDao genericDao
;
143 private IDescriptionService descriptionService
;
146 private IOrderedTermVocabularyDao orderedVocabularyDao
;
149 private IOccurrenceDao occurrenceDao
;
152 private AbstractBeanInitializer beanInitializer
;
155 private ILuceneIndexToolProvider luceneIndexToolProvider
;
161 public TaxonServiceImpl(){
162 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
166 * FIXME Candidate for harmonization
167 * rename searchByName ?
170 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
171 return dao
.getTaxaByName(name
, sec
);
175 * FIXME Candidate for harmonization
176 * list(Synonym.class, ...)
178 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
181 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
182 return dao
.getAllSynonyms(limit
, start
);
186 * FIXME Candidate for harmonization
187 * list(Taxon.class, ...)
189 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
192 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
193 return dao
.getAllTaxa(limit
, start
);
197 * FIXME Candidate for harmonization
198 * merge with getRootTaxa(Reference sec, ..., ...)
200 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
203 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
204 if (cdmFetch
== null){
205 cdmFetch
= CdmFetch
.NO_FETCH();
207 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
212 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
215 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
216 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
220 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
223 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
224 return dao
.getAllRelationships(limit
, start
);
228 * FIXME Candidate for harmonization
229 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
233 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
235 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
236 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
237 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
238 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
239 return taxonRelTypeVocabulary
;
246 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
249 @Transactional(readOnly
= false)
250 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
252 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
253 synonymName
.removeTaxonBase(synonym
);
254 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
255 taxonName
.removeTaxonBase(acceptedTaxon
);
257 synonym
.setName(taxonName
);
258 acceptedTaxon
.setName(synonymName
);
260 // the accepted taxon needs a new uuid because the concept has changed
261 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
262 //acceptedTaxon.setUuid(UUID.randomUUID());
267 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
269 //TODO correct delete handling still needs to be implemented / checked
271 @Transactional(readOnly
= false)
272 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
274 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
275 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
276 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
278 //check synonym is not homotypic
279 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
280 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
281 throw new HomotypicalGroupChangeException(message
);
284 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
286 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
287 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
289 for (Synonym heteroSynonym
: heteroSynonyms
){
290 if (synonym
.equals(heteroSynonym
)){
291 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
293 //move synonyms in same homotypic group to new accepted taxon
294 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
298 //synonym.getName().removeTaxonBase(synonym);
299 //TODO correct delete handling still needs to be implemented / checked
301 // deleteSynonym(synonym, taxon, false);
304 this.delete(synonym
);
306 } catch (Exception e
) {
307 logger
.info("Can't delete old synonym from database");
311 return newAcceptedTaxon
;
316 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
318 // Get name from synonym
319 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
321 // remove synonym from taxon
322 toTaxon
.removeSynonym(synonym
);
324 // Create a taxon with synonym name
325 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
327 // Add taxon relation
328 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
330 // since we are swapping names, we have to detach the name from the synonym completely.
331 // Otherwise the synonym will still be in the list of typified names.
332 synonym
.getName().removeTaxonBase(synonym
);
339 * @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)
341 @Transactional(readOnly
= false)
343 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
344 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
346 TaxonNameBase synonymName
= synonym
.getName();
347 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
351 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
352 newHomotypicalGroup
.addTypifiedName(synonymName
);
354 //remove existing basionym relationships
355 synonymName
.removeBasionyms();
357 //add basionym relationship
358 if (setBasionymRelationIfApplicable
){
359 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
360 for (TaxonNameBase basionym
: basionyms
){
361 synonymName
.addBasionym(basionym
);
365 //set synonym relationship correctly
366 // SynonymRelationship relToTaxon = null;
367 boolean relToTargetTaxonExists
= false;
368 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
369 for (SynonymRelationship rel
: existingRelations
){
370 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
371 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
372 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
373 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
374 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
375 rel
.setType(newRelationType
);
376 //TODO handle citation and microCitation
379 relToTargetTaxonExists
= true;
381 if (removeFromOtherTaxa
){
382 acceptedTaxon
.removeSynonym(synonym
, false);
388 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
389 Taxon acceptedTaxon
= targetTaxon
;
390 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
391 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
392 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
393 //TODO handle citation and microCitation
394 Reference citation
= null;
395 String microCitation
= null;
396 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
403 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
406 @Transactional(readOnly
= false)
407 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
409 clazz
= TaxonBase
.class;
411 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
416 protected void setDao(ITaxonDao dao
) {
421 * @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)
424 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
,
425 String uninomial
, String infragenericEpithet
, String specificEpithet
,
426 String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
427 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
429 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
430 if(numberOfResults
> 0) { // no point checking again
431 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
434 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
439 * @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)
442 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
443 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
445 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
446 if(numberOfResults
> 0) { // no point checking again
447 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
454 * @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)
457 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
458 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
460 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
461 if(numberOfResults
> 0) { // no point checking again
462 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
468 * @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)
471 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
472 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
474 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
475 if(numberOfResults
> 0) { // no point checking again
476 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
478 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
482 * @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)
485 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
486 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
488 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
489 if(numberOfResults
> 0) { // no point checking again
490 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
496 * @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)
499 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
500 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
502 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
503 if(numberOfResults
> 0) { // no point checking again
504 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
506 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
511 * @param includeRelationships
515 * @param propertyPaths
516 * @return an List which is not specifically ordered
519 public Set
<Taxon
> listRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Integer maxDepth
,
520 Integer limit
, Integer start
, List
<String
> propertyPaths
) {
522 Set
<Taxon
> relatedTaxa
= collectRelatedTaxa(taxon
, includeRelationships
, new HashSet
<Taxon
>(), maxDepth
);
523 relatedTaxa
.remove(taxon
);
524 beanInitializer
.initializeAll(relatedTaxa
, propertyPaths
);
530 * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the
531 * <code>taxon</code> supplied as parameter.
534 * @param includeRelationships
536 * @param maxDepth can be <code>null</code> for infinite depth
539 private Set
<Taxon
> collectRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Set
<Taxon
> taxa
, Integer maxDepth
) {
545 if(maxDepth
!= null) {
548 if(logger
.isDebugEnabled()){
549 logger
.debug("collecting related taxa for " + taxon
+ " with maxDepth=" + maxDepth
);
551 List
<TaxonRelationship
> taxonRelationships
= dao
.getTaxonRelationships(taxon
, null, null, null, null, null, null);
552 for (TaxonRelationship taxRel
: taxonRelationships
) {
555 if (taxRel
.getToTaxon() == null || taxRel
.getFromTaxon() == null || taxRel
.getType() == null) {
558 // filter by includeRelationships
559 for (TaxonRelationshipEdge relationshipEdgeFilter
: includeRelationships
) {
560 if ( relationshipEdgeFilter
.getTaxonRelationshipType().equals(taxRel
.getType()) ) {
561 if (relationshipEdgeFilter
.getDirections().contains(Direction
.relatedTo
) && !taxa
.contains(taxRel
.getToTaxon())) {
562 if(logger
.isDebugEnabled()){
563 logger
.debug(maxDepth
+ ": " + taxon
.getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxRel
.getToTaxon().getTitleCache());
565 taxa
.add(taxRel
.getToTaxon());
566 if(maxDepth
== null || maxDepth
> 0) {
567 taxa
.addAll(collectRelatedTaxa(taxRel
.getToTaxon(), includeRelationships
, taxa
, maxDepth
));
570 if(relationshipEdgeFilter
.getDirections().contains(Direction
.relatedFrom
) && !taxa
.contains(taxRel
.getFromTaxon())) {
571 taxa
.add(taxRel
.getFromTaxon());
572 if(logger
.isDebugEnabled()){
573 logger
.debug(maxDepth
+ ": " +taxRel
.getFromTaxon().getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxon
.getTitleCache() );
575 if(maxDepth
== null || maxDepth
> 0) {
576 taxa
.addAll(collectRelatedTaxa(taxRel
.getFromTaxon(), includeRelationships
, taxa
, maxDepth
));
586 * @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)
589 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
590 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
592 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
593 if(numberOfResults
> 0) { // no point checking again
594 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
597 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
601 * @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)
604 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
605 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
607 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
608 if(numberOfResults
> 0) { // no point checking again
609 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
612 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
616 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
619 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
620 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
621 return t
.getHomotypicSynonymsByHomotypicGroup();
625 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
628 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
629 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
630 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
631 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
632 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
633 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
635 return heterotypicSynonymyGroups
;
639 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
641 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
642 // Class<? extends TaxonBase> clazz = null;
643 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
644 // clazz = TaxonBase.class;
645 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
646 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
647 // } else if(configurator.isDoTaxa()) {
648 // clazz = Taxon.class;
649 // //propertyPath = configurator.getTaxonPropertyPath();
650 // } else if (configurator.isDoSynonyms()) {
651 // clazz = Synonym.class;
652 // //propertyPath = configurator.getSynonymPropertyPath();
656 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
661 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
664 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
666 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
667 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
668 List
<TaxonBase
> taxa
= null;
671 long numberTaxaResults
= 0L;
674 List
<String
> propertyPath
= new ArrayList
<String
>();
675 if(configurator
.getTaxonPropertyPath() != null){
676 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
680 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
681 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
683 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
684 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
685 configurator
.getNamedAreas());
688 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
689 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
690 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
691 configurator
.getMatchMode(), configurator
.getNamedAreas(),
692 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
696 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
699 results
.addAll(taxa
);
702 numberOfResults
+= numberTaxaResults
;
704 // Names without taxa
705 if (configurator
.isDoNamesWithoutTaxa()) {
706 int numberNameResults
= 0;
708 List
<?
extends TaxonNameBase
<?
,?
>> names
=
709 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
710 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
711 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
712 if (names
.size() > 0) {
713 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
714 if (taxonName
.getTaxonBases().size() == 0) {
715 results
.add(taxonName
);
719 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
720 numberOfResults
+= numberNameResults
;
724 // Taxa from common names
726 if (configurator
.isDoTaxaByCommonNames()) {
727 taxa
= new ArrayList
<TaxonBase
>();
728 numberTaxaResults
= 0;
729 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
730 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
732 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
733 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
734 for( Object
[] entry
: commonNameResults
) {
735 taxa
.add((TaxonBase
) entry
[0]);
739 results
.addAll(taxa
);
741 numberOfResults
+= numberTaxaResults
;
745 return new DefaultPagerImpl
<IdentifiableEntity
>
746 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
749 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
750 return dao
.getUuidAndTitleCache();
754 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
757 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
758 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
759 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
760 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
761 for (TaxonDescription taxDesc
: descriptions
){
762 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
763 for (DescriptionElementBase descElem
: elements
){
764 for(Media media
: descElem
.getMedia()){
766 //find the best matching representation
767 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
776 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
779 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, boolean limitToGalleries
, List
<String
> propertyPath
){
780 return listMedia(taxon
, includeRelationships
, limitToGalleries
, true, false, false, propertyPath
);
785 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)
788 public List
<Media
> listMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
789 Boolean limitToGalleries
, Boolean includeTaxonDescriptions
, Boolean includeOccurrences
,
790 Boolean includeTaxonNameDescriptions
, List
<String
> propertyPath
) {
792 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
793 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
795 if (limitToGalleries
== null) {
796 limitToGalleries
= false;
799 // --- resolve related taxa
800 if (includeRelationships
!= null) {
801 taxa
= listRelatedTaxa(taxon
, includeRelationships
, null, null, null, null);
804 taxa
.add((Taxon
) dao
.load(taxon
.getUuid()));
806 if(includeTaxonDescriptions
!= null && includeTaxonDescriptions
){
807 List
<TaxonDescription
> taxonDescriptions
= new ArrayList
<TaxonDescription
>();
808 // --- TaxonDescriptions
809 for (Taxon t
: taxa
) {
810 taxonDescriptions
.addAll(descriptionService
.listTaxonDescriptions(t
, null, null, null, null, propertyPath
));
812 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
813 if (!limitToGalleries
|| taxonDescription
.isImageGallery()) {
814 for (DescriptionElementBase element
: taxonDescription
.getElements()) {
815 for (Media media
: element
.getMedia()) {
816 taxonMedia
.add(media
);
823 if(includeOccurrences
!= null && includeOccurrences
) {
824 Set
<SpecimenOrObservationBase
> specimensOrObservations
= new HashSet
<SpecimenOrObservationBase
>();
826 for (Taxon t
: taxa
) {
827 specimensOrObservations
.addAll(occurrenceDao
.listByAssociatedTaxon(null, t
, null, null, null, null));
829 for (SpecimenOrObservationBase occurrence
: specimensOrObservations
) {
831 taxonMedia
.addAll(occurrence
.getMedia());
833 // SpecimenDescriptions
834 Set
<SpecimenDescription
> specimenDescriptions
= occurrence
.getSpecimenDescriptions();
835 for (DescriptionBase specimenDescription
: specimenDescriptions
) {
836 if (!limitToGalleries
|| specimenDescription
.isImageGallery()) {
837 Set
<DescriptionElementBase
> elements
= specimenDescription
.getElements();
838 for (DescriptionElementBase element
: elements
) {
839 for (Media media
: element
.getMedia()) {
840 taxonMedia
.add(media
);
847 if (occurrence
instanceof DerivedUnitBase
) {
848 if (((DerivedUnitBase
) occurrence
).getCollection() != null){
849 taxonMedia
.addAll(((DerivedUnitBase
) occurrence
).getCollection().getMedia());
854 if (occurrence
instanceof DnaSample
) {
855 Set
<Sequence
> sequences
= ((DnaSample
) occurrence
).getSequences();
856 for (Sequence sequence
: sequences
) {
857 taxonMedia
.addAll(sequence
.getChromatograms());
864 if(includeTaxonNameDescriptions
!= null && includeTaxonNameDescriptions
) {
865 // --- TaxonNameDescription
866 Set
<TaxonNameDescription
> nameDescriptions
= new HashSet
<TaxonNameDescription
>();
867 for (Taxon t
: taxa
) {
868 nameDescriptions
.addAll(t
.getName().getDescriptions());
870 for(TaxonNameDescription nameDescription
: nameDescriptions
){
871 if (!limitToGalleries
|| nameDescription
.isImageGallery()) {
872 Set
<DescriptionElementBase
> elements
= nameDescription
.getElements();
873 for (DescriptionElementBase element
: elements
) {
874 for (Media media
: element
.getMedia()) {
875 taxonMedia
.add(media
);
882 beanInitializer
.initializeAll(taxonMedia
, propertyPath
);
887 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
890 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
891 return this.dao
.listByIds(listOfIDs
, null, null, null, null);
895 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
898 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
899 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
903 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
906 public int countAllRelationships() {
907 return this.dao
.countAllRelationships();
914 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
917 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
918 return this.dao
.findIdenticalTaxonNames(propertyPath
);
923 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
926 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
928 config
= new TaxonDeletionConfigurator();
932 if (! config
.isDeleteTaxonNodes()){
933 if (taxon
.getTaxonNodes().size() > 0){
934 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
935 throw new ReferencedObjectUndeletableException(message
);
940 // SynonymRelationShip
941 if (config
.isDeleteSynonymRelations()){
942 boolean removeSynonymNameFromHomotypicalGroup
= false;
943 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
944 Synonym synonym
= synRel
.getSynonym();
945 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
946 if (config
.isDeleteSynonymsIfPossible()){
948 boolean newHomotypicGroupIfNeeded
= true;
949 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
951 deleteSynonymRelationships(synonym
, taxon
);
957 if (! config
.isDeleteTaxonRelationships()){
958 if (taxon
.getTaxonRelations().size() > 0){
959 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.";
960 throw new ReferencedObjectUndeletableException(message
);
966 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
968 for (TaxonDescription desc
: descriptions
){
969 if (config
.isDeleteDescriptions()){
970 //TODO use description delete configurator ?
971 //FIXME check if description is ALWAYS deletable
972 descriptionService
.delete(desc
);
974 if (desc
.getDescribedSpecimenOrObservations().size()>0){
975 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
976 " which also describes specimens or abservations";
977 throw new ReferencedObjectUndeletableException(message
);
983 //check references with only reverse mapping
984 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
985 for (CdmBase referencingObject
: referencingObjects
){
986 //IIdentificationKeys (Media, Polytomous, MultiAccess)
987 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
988 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
989 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
990 throw new ReferencedObjectUndeletableException(message
);
995 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
996 String message
= "Taxon can't be deleted as it is used in polytomous key node";
997 throw new ReferencedObjectUndeletableException(message
);
1001 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
1002 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
1003 throw new ReferencedObjectUndeletableException(message
);
1009 if (config
.isDeleteNameIfPossible()){
1011 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
1012 } catch (ReferencedObjectUndeletableException e
) {
1014 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
1021 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1023 @Transactional(readOnly
= false)
1025 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
1026 if (synonym
== null){
1029 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
1031 //remove synonymRelationship
1032 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
1034 taxonSet
.add(taxon
);
1036 taxonSet
.addAll(synonym
.getAcceptedTaxa());
1038 for (Taxon relatedTaxon
: taxonSet
){
1039 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
1040 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
1042 this.saveOrUpdate(synonym
);
1044 //TODO remove name from homotypical group?
1046 //remove synonym (if necessary)
1047 if (synonym
.getSynonymRelations().isEmpty()){
1048 TaxonNameBase
<?
,?
> name
= synonym
.getName();
1049 synonym
.setName(null);
1050 dao
.delete(synonym
);
1052 //remove name if possible (and required)
1053 if (name
!= null && removeNameIfPossible
){
1055 nameService
.delete(name
, new NameDeletionConfigurator());
1056 }catch (DataChangeNoRollbackException ex
){
1057 if (logger
.isDebugEnabled()) {
1058 logger
.debug("Name wasn't deleted as it is referenced");
1067 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
1070 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
1072 return this.dao
.findIdenticalNamesNew(propertyPath
);
1076 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1079 public String
getPhylumName(TaxonNameBase name
){
1080 return this.dao
.getPhylumName(name
);
1084 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
1087 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
1088 return dao
.deleteSynonymRelationships(syn
, taxon
);
1092 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
1095 public long deleteSynonymRelationships(Synonym syn
) {
1096 return dao
.deleteSynonymRelationships(syn
, null);
1101 * @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)
1104 public List
<SynonymRelationship
> listSynonymRelationships(
1105 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
1106 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
1107 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
1109 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
1110 if(numberOfResults
> 0) { // no point checking again
1111 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
1117 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
1120 public Taxon
findBestMatchingTaxon(String taxonName
) {
1121 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
1122 config
.setTaxonNameTitle(taxonName
);
1123 return findBestMatchingTaxon(config
);
1129 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
1131 Taxon bestCandidate
= null;
1133 // 1. search for acceptet taxa
1134 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1135 boolean bestCandidateMatchesSecUuid
= false;
1136 boolean bestCandidateIsInClassification
= false;
1137 int countEqualCandidates
= 0;
1138 for(TaxonBase taxonBaseCandidate
: taxonList
){
1139 if(taxonBaseCandidate
instanceof Taxon
){
1140 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
1141 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
1142 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
1144 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
1145 bestCandidate
= newCanditate
;
1146 countEqualCandidates
= 1;
1147 bestCandidateMatchesSecUuid
= true;
1151 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
1152 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
1154 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
1155 bestCandidate
= newCanditate
;
1156 countEqualCandidates
= 1;
1157 bestCandidateIsInClassification
= true;
1160 if (bestCandidate
== null){
1161 bestCandidate
= newCanditate
;
1162 countEqualCandidates
= 1;
1166 }else{ //not Taxon.class
1169 countEqualCandidates
++;
1172 if (bestCandidate
!= null){
1173 if(countEqualCandidates
> 1){
1174 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
1175 return bestCandidate
;
1177 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
1178 return bestCandidate
;
1183 // 2. search for synonyms
1184 if (config
.isIncludeSynonyms()){
1185 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1186 for(TaxonBase taxonBase
: synonymList
){
1187 if(taxonBase
instanceof Synonym
){
1188 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
1189 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
1190 if(!acceptetdCandidates
.isEmpty()){
1191 bestCandidate
= acceptetdCandidates
.iterator().next();
1192 if(acceptetdCandidates
.size() == 1){
1193 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
1194 return bestCandidate
;
1196 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
1197 return bestCandidate
;
1199 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
1205 } catch (Exception e
){
1207 e
.printStackTrace();
1210 return bestCandidate
;
1213 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
1214 UUID configClassificationUuid
= config
.getClassificationUuid();
1215 if (configClassificationUuid
== null){
1218 for (TaxonNode node
: taxon
.getTaxonNodes()){
1219 UUID classUuid
= node
.getClassification().getUuid();
1220 if (configClassificationUuid
.equals(classUuid
)){
1227 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1228 UUID configSecUuid
= config
.getSecUuid();
1229 if (configSecUuid
== null){
1232 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1233 return configSecUuid
.equals(taxonSecUuid
);
1237 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1240 public Synonym
findBestMatchingSynonym(String taxonName
) {
1241 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1242 if(! synonymList
.isEmpty()){
1243 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1244 if(synonymList
.size() == 1){
1245 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1248 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1257 * @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)
1260 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1261 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1263 Synonym synonym
= oldSynonymRelation
.getSynonym();
1264 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1265 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1266 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1267 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1268 //set default relationship type
1269 if (newSynonymRelationshipType
== null){
1270 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1272 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1274 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1275 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1276 boolean isSingleInGroup
= !(hgSize
> 1);
1278 if (! isSingleInGroup
){
1279 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1280 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1281 if (isHomotypicToAccepted
){
1282 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.";
1283 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1284 message
= String
.format(message
, homotypicRelatives
);
1285 throw new HomotypicalGroupChangeException(message
);
1287 if (! moveHomotypicGroup
){
1288 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.";
1289 throw new HomotypicalGroupChangeException(message
);
1292 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1294 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1296 SynonymRelationship result
= null;
1297 //move all synonyms to new taxon
1298 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1299 for (Synonym syn
: homotypicSynonyms
){
1300 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1301 for (SynonymRelationship synRelation
: synRelations
){
1302 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1303 Reference
<?
> newReference
= reference
;
1304 if (newReference
== null && keepReference
){
1305 newReference
= synRelation
.getCitation();
1307 String newRefDetail
= referenceDetail
;
1308 if (newRefDetail
== null && keepReference
){
1309 newRefDetail
= synRelation
.getCitationMicroReference();
1311 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1312 fromTaxon
.removeSynonymRelation(synRelation
, false);
1314 //change homotypic group of synonym if relType is 'homotypic'
1315 // if (newRelTypeIsHomotypic){
1316 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1319 if (synRelation
.equals(oldSynonymRelation
)){
1320 result
= newSynRelation
;
1326 saveOrUpdate(newTaxon
);
1327 //Assert that there is a result
1328 if (result
== null){
1329 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1330 throw new IllegalStateException(message
);
1336 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1339 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1340 return dao
.getUuidAndTitleCacheTaxon();
1344 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1347 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1348 return dao
.getUuidAndTitleCacheSynonym();
1352 * @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)
1355 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1356 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1357 Classification classification
, List
<Language
> languages
,
1358 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1361 LuceneSearch luceneSearch
= prepareFindByFullTextSearch(clazz
, queryString
, classification
, languages
, highlightFragments
);
1363 // --- execute search
1364 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1366 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1367 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1369 // --- initialize taxa, thighlight matches ....
1370 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1371 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1372 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1374 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1375 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1379 public Pager
<SearchResult
<TaxonBase
>> findByDistribution(List
<NamedArea
> areaFilter
, List
<PresenceAbsenceTermBase
<?
>> statusFilter
,
1380 Classification classification
,
1381 Integer pageSize
, Integer pageNumber
,
1382 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws IOException
, ParseException
{
1384 LuceneSearch luceneSearch
= prepareByDistributionSearch(areaFilter
, statusFilter
, classification
);
1386 // --- execute search
1387 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1389 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1390 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1392 // --- initialize taxa, thighlight matches ....
1393 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1394 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1395 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1397 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1398 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1403 * @param queryString
1404 * @param classification
1406 * @param highlightFragments
1407 * @param directorySelectClass
1410 protected LuceneSearch
prepareFindByFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Language
> languages
,
1411 boolean highlightFragments
) {
1412 BooleanQuery finalQuery
= new BooleanQuery();
1413 BooleanQuery textQuery
= new BooleanQuery();
1415 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, TaxonBase
.class);
1416 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1418 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1419 luceneSearch
.setSortFields(sortFields
);
1421 // ---- search criteria
1422 luceneSearch
.setCdmTypRestriction(clazz
);
1424 textQuery
.add(taxonBaseQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1425 textQuery
.add(taxonBaseQueryFactory
.newDefinedTermQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1427 finalQuery
.add(textQuery
, Occur
.MUST
);
1429 if(classification
!= null){
1430 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1432 luceneSearch
.setQuery(finalQuery
);
1434 if(highlightFragments
){
1435 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1437 return luceneSearch
;
1441 * Uses org.apache.lucene.search.join.JoinUtil for query time joining, alternatively
1442 * the BlockJoinQuery could be used. The latter might be more memory save but has the
1443 * drawback of requiring to do the join an indexing time.
1444 * see http://dev.e-taxonomy.eu/trac/wiki/LuceneNotes#JoinsinLucene for more information on this.
1446 * Joins TaxonRelationShip with Taxon depending on the direction of the given edge:
1448 * <li>direct, everted: {@link Direction.relatedTo}: TaxonRelationShip.relatedTo.id --> Taxon.id </li>
1449 * <li>inverse: {@link Direction.relatedFrom}: TaxonRelationShip.relatedFrom.id --> Taxon.id </li>
1452 * @param queryString
1453 * @param classification
1455 * @param highlightFragments
1457 * @throws IOException
1459 protected LuceneSearch
prepareFindByTaxonRelationFullTextSearch(TaxonRelationshipEdge edge
, String queryString
, Classification classification
, List
<Language
> languages
,
1460 boolean highlightFragments
) throws IOException
{
1463 String queryTermField
;
1464 String toField
= "id"; // TaxonBase.uuid
1466 if(edge
.isBidirectional()){
1467 throw new RuntimeException("Bidirectional joining not supported!");
1470 fromField
= "relatedFrom.id";
1471 queryTermField
= "relatedFrom.titleCache";
1472 } else if(edge
.isInvers()) {
1473 fromField
= "relatedTo.id";
1474 queryTermField
= "relatedTo.titleCache";
1476 throw new RuntimeException("Invalid direction: " + edge
.getDirections());
1479 BooleanQuery finalQuery
= new BooleanQuery();
1481 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonBase
.class);
1482 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1484 BooleanQuery joinFromQuery
= new BooleanQuery();
1485 joinFromQuery
.add(taxonBaseQueryFactory
.newTermQuery(queryTermField
, queryString
), Occur
.MUST
);
1486 joinFromQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("type.id", edge
.getTaxonRelationshipType()), Occur
.MUST
);
1487 Query joinQuery
= taxonBaseQueryFactory
.newJoinQuery(fromField
, toField
, joinFromQuery
, TaxonRelationship
.class);
1489 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1490 luceneSearch
.setSortFields(sortFields
);
1492 finalQuery
.add(joinQuery
, Occur
.MUST
);
1494 if(classification
!= null){
1495 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1497 luceneSearch
.setQuery(finalQuery
);
1499 if(highlightFragments
){
1500 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1502 return luceneSearch
;
1509 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNamesByFullText(java.util.EnumSet, java.lang.String, eu.etaxonomy.cdm.model.taxon.Classification, java.util.Set, java.util.List, boolean, java.lang.Integer, java.lang.Integer, java.util.List, java.util.Map)
1512 public Pager
<SearchResult
<TaxonBase
>> findTaxaAndNamesByFullText(
1513 EnumSet
<TaxaAndNamesSearchMode
> searchModes
, String queryString
, Classification classification
,
1514 Set
<NamedArea
> namedAreas
, Set
<PresenceAbsenceTermBase
<?
>> distributionStatus
, List
<Language
> languages
,
1515 boolean highlightFragments
, Integer pageSize
,
1516 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
)
1517 throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
1519 if(highlightFragments
){
1520 logger
.warn("findTaxaAndNamesByFullText() : fragment highlighting is " +
1521 "currently not fully supported by this method and thus " +
1522 "may not work with common names and misapplied names.");
1525 // convert sets to lists
1526 List
<NamedArea
> namedAreaList
= null;
1527 List
<PresenceAbsenceTermBase
<?
>>distributionStatusList
= null;
1528 if(namedAreas
!= null){
1529 namedAreaList
= new ArrayList
<NamedArea
>(namedAreas
.size());
1530 namedAreaList
.addAll(namedAreas
);
1532 if(distributionStatus
!= null){
1533 distributionStatusList
= new ArrayList
<PresenceAbsenceTermBase
<?
>>(distributionStatus
.size());
1534 distributionStatusList
.addAll(distributionStatus
);
1537 // set default if parameter is null
1538 if(searchModes
== null){
1539 searchModes
= EnumSet
.of(TaxaAndNamesSearchMode
.doTaxa
);
1542 boolean addDistributionFilter
= namedAreas
!= null && namedAreas
.size() > 0;
1544 List
<LuceneSearch
> luceneSearches
= new ArrayList
<LuceneSearch
>();
1545 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1548 ======== filtering by distribution , HOWTO ========
1550 - http://www.javaranch.com/journal/2009/02/filtering-a-lucene-search.html
1551 - http://stackoverflow.com/questions/17709256/lucene-solr-using-complex-filters -> QueryWrapperFilter
1552 add Filter to search as http://lucene.apache.org/core/3_6_0/api/all/org/apache/lucene/search/Filter.html
1553 which will be put into a FilteredQuersy in the end ?
1556 3. how does it work in spatial?
1558 - http://www.nsshutdown.com/projects/lucene/whitepaper/locallucene_v2.html
1559 - http://www.infoq.com/articles/LuceneSpatialSupport
1560 - http://www.mhaller.de/archives/156-Spatial-search-with-Lucene.html
1561 ------------------------------------------------------------------------
1564 A) use a separate distribution filter per index sub-query/search:
1565 - byTaxonSyonym (query TaxaonBase):
1566 use a join area filter (Distribution -> TaxonBase)
1567 - byCommonName (query DescriptionElementBase): use an area filter on
1568 DescriptionElementBase !!! PROBLEM !!!
1569 This cannot work since the distributions are different entities than the
1570 common names and thus these are different lucene documents.
1571 - byMisaplliedNames (join query TaxonRelationship -> TaxaonBase):
1572 use a join area filter (Distribution -> TaxonBase)
1574 B) use a common distribution filter for all index sub-query/searches:
1575 - use a common join area filter (Distribution -> TaxonBase)
1576 - also implement the byCommonName as join query (CommonName -> TaxonBase)
1577 PROBLEM in this case: we are losing the fragment highlighting for the
1578 common names, since the returned documents are always TaxonBases
1581 /* The QueryFactory for creating filter queries on Distributions should
1582 * The query factory used for the common names query cannot be reused
1583 * for this case, since we want to only record the text fields which are
1584 * actually used in the primary query
1586 QueryFactory distributionFilterQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Distribution
.class);
1588 BooleanFilter multiIndexByAreaFilter
= new BooleanFilter();
1591 // search for taxa or synonyms
1592 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) || searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1593 Class taxonBaseSubclass
= TaxonBase
.class;
1594 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && !searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1595 taxonBaseSubclass
= Taxon
.class;
1596 } else if (!searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1597 taxonBaseSubclass
= Synonym
.class;
1599 luceneSearches
.add(prepareFindByFullTextSearch(taxonBaseSubclass
, queryString
, classification
, languages
, highlightFragments
));
1600 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1601 /* A) does not work!!!!
1602 if(addDistributionFilter){
1603 // in this case we need a filter which uses a join query
1604 // to get the TaxonBase documents for the DescriptionElementBase documents
1605 // which are matching the areas in question
1606 Query taxonAreaJoinQuery = createByDistributionJoinQuery(
1608 distributionStatusList,
1609 distributionFilterQueryFactory
1611 multiIndexByAreaFilter.add(new QueryWrapperFilter(taxonAreaJoinQuery), Occur.SHOULD);
1614 if(searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1615 // add additional area filter for synonyms
1616 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
1617 String toField
= "accTaxon.id"; // id in TaxonBase index
1619 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, distributionFilterQueryFactory
);
1621 Query taxonAreaJoinQuery
= distributionFilterQueryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
1622 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
1627 // search by CommonTaxonName
1628 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxaByCommonNames
)) {
1630 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
1631 Query byCommonNameJoinQuery
= descriptionElementQueryFactory
.newJoinQuery(
1632 "inDescription.taxon.id",
1634 createByDescriptionElementFullTextQuery(queryString
, classification
, null, languages
, descriptionElementQueryFactory
),
1635 CommonTaxonName
.class);
1636 logger
.debug("byCommonNameJoinQuery: " + byCommonNameJoinQuery
.toString());
1637 LuceneSearch byCommonNameSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
1638 byCommonNameSearch
.setCdmTypRestriction(Taxon
.class);
1639 byCommonNameSearch
.setQuery(byCommonNameJoinQuery
);
1640 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1642 luceneSearches
.add(byCommonNameSearch
);
1644 /* A) does not work!!!!
1646 prepareByDescriptionElementFullTextSearch(CommonTaxonName.class,
1647 queryString, classification, null, languages, highlightFragments)
1649 idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id");
1650 if(addDistributionFilter){
1651 // in this case we are able to use DescriptionElementBase documents
1652 // which are matching the areas in question directly
1653 BooleanQuery byDistributionQuery = createByDistributionQuery(
1655 distributionStatusList,
1656 distributionFilterQueryFactory
1658 multiIndexByAreaFilter.add(new QueryWrapperFilter(byDistributionQuery), Occur.SHOULD);
1662 // search by misapplied names
1663 if(searchModes
.contains(TaxaAndNamesSearchMode
.doMisappliedNames
)) {
1665 // prepareFindByTaxonRelationFullTextSearch() is making use of JoinUtil.createJoinQuery()
1666 // which allows doing query time joins
1667 // finds the misapplied name (Taxon B) which is an misapplication for
1668 // a related Taxon A.
1670 // A distribiution filter must two joins in this case:
1671 // Distribution.inDescription.taxon.id -join-> TaxonRelationship.relatedFrom.id in MISAPPLIED_NAME_FOR -join-> taxon.id
1672 luceneSearches
.add(prepareFindByTaxonRelationFullTextSearch(
1673 new TaxonRelationshipEdge(TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), Direction
.relatedTo
),
1674 queryString
, classification
, languages
, highlightFragments
));
1675 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1678 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
,
1679 luceneSearches
.toArray(new LuceneSearch
[luceneSearches
.size()]));
1682 if(addDistributionFilter
){
1685 // in this case we need a filter which uses a join query
1686 // to get the TaxonBase documents for the DescriptionElementBase documents
1687 // which are matching the areas in question
1689 // for toTaxa, doByCommonName
1690 Query taxonAreaJoinQuery
= createByDistributionJoinQuery(
1692 distributionStatusList
,
1693 distributionFilterQueryFactory
1695 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
1698 if (addDistributionFilter
){
1699 multiSearch
.setFilter(multiIndexByAreaFilter
);
1701 // --- execute search
1702 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1704 // --- initialize taxa, highlight matches ....
1705 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1708 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1709 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1711 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1712 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1716 * @param namedAreaList at least one area must be in the list
1717 * @param distributionStatusList optional
1719 * @throws IOException
1721 protected Query
createByDistributionJoinQuery(
1722 List
<NamedArea
> namedAreaList
,
1723 List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
,
1724 QueryFactory queryFactory
1725 ) throws IOException
{
1727 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
1728 String toField
= "id"; // id in TaxonBase index
1730 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, queryFactory
);
1732 Query taxonAreaJoinQuery
= queryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
1734 return taxonAreaJoinQuery
;
1738 * @param namedAreaList
1739 * @param distributionStatusList
1740 * @param queryFactory
1743 private BooleanQuery
createByDistributionQuery(List
<NamedArea
> namedAreaList
,
1744 List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
, QueryFactory queryFactory
) {
1745 BooleanQuery areaQuery
= new BooleanQuery();
1746 // area field from Distribution
1747 areaQuery
.add(queryFactory
.newEntityIdsQuery("area.id", namedAreaList
), Occur
.MUST
);
1749 // status field from Distribution
1750 if(distributionStatusList
!= null && distributionStatusList
.size() > 0){
1751 areaQuery
.add(queryFactory
.newEntityIdsQuery("status.id", distributionStatusList
), Occur
.MUST
);
1754 logger
.debug("createByDistributionQuery() query: " + areaQuery
.toString());
1759 * This method has been primarily created for testing the area join query but might
1760 * also be useful in other situations
1762 * @param namedAreaList
1763 * @param distributionStatusList
1764 * @param classification
1765 * @param highlightFragments
1767 * @throws IOException
1769 protected LuceneSearch
prepareByDistributionSearch(
1770 List
<NamedArea
> namedAreaList
, List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
,
1771 Classification classification
) throws IOException
{
1773 BooleanQuery finalQuery
= new BooleanQuery();
1775 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
1777 // FIXME is this query factory using the wrong type?
1778 QueryFactory taxonQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Taxon
.class);
1780 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1781 luceneSearch
.setSortFields(sortFields
);
1784 Query byAreaQuery
= createByDistributionJoinQuery(namedAreaList
, distributionStatusList
, taxonQueryFactory
);
1786 finalQuery
.add(byAreaQuery
, Occur
.MUST
);
1788 if(classification
!= null){
1789 finalQuery
.add(taxonQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1792 logger
.info("prepareByAreaSearch() query: " + finalQuery
.toString());
1793 luceneSearch
.setQuery(finalQuery
);
1795 return luceneSearch
;
1801 * @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)
1804 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1805 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1806 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1807 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1810 LuceneSearch luceneSearch
= prepareByDescriptionElementFullTextSearch(clazz
, queryString
, classification
, features
, languages
, highlightFragments
);
1812 // --- execute search
1813 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1815 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1816 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1818 // --- initialize taxa, highlight matches ....
1819 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1820 @SuppressWarnings("rawtypes")
1821 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1822 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1824 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1825 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1831 public Pager
<SearchResult
<TaxonBase
>> findByEverythingFullText(String queryString
,
1832 Classification classification
, List
<Language
> languages
, boolean highlightFragments
,
1833 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
1835 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, null, languages
, highlightFragments
);
1836 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
);
1838 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
, luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
1840 // --- execute search
1841 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1843 // --- initialize taxa, highlight matches ....
1844 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1846 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1847 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1848 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1850 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1851 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1853 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1854 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1861 * @param queryString
1862 * @param classification
1865 * @param highlightFragments
1866 * @param directorySelectClass
1869 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
,
1870 String queryString
, Classification classification
, List
<Feature
> features
,
1871 List
<Language
> languages
, boolean highlightFragments
) {
1873 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, DescriptionElementBase
.class);
1874 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
1876 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", SortField
.STRING
, false)};
1878 BooleanQuery finalQuery
= createByDescriptionElementFullTextQuery(queryString
, classification
, features
,
1879 languages
, descriptionElementQueryFactory
);
1881 luceneSearch
.setSortFields(sortFields
);
1882 luceneSearch
.setCdmTypRestriction(clazz
);
1883 luceneSearch
.setQuery(finalQuery
);
1884 if(highlightFragments
){
1885 luceneSearch
.setHighlightFields(descriptionElementQueryFactory
.getTextFieldNamesAsArray());
1888 return luceneSearch
;
1892 * @param queryString
1893 * @param classification
1896 * @param descriptionElementQueryFactory
1899 private BooleanQuery
createByDescriptionElementFullTextQuery(String queryString
, Classification classification
,
1900 List
<Feature
> features
, List
<Language
> languages
, QueryFactory descriptionElementQueryFactory
) {
1901 BooleanQuery finalQuery
= new BooleanQuery();
1902 BooleanQuery textQuery
= new BooleanQuery();
1903 textQuery
.add(descriptionElementQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1907 if(languages
== null || languages
.size() == 0){
1908 nameQuery
= descriptionElementQueryFactory
.newTermQuery("name", queryString
);
1910 nameQuery
= new BooleanQuery();
1911 BooleanQuery languageSubQuery
= new BooleanQuery();
1912 for(Language lang
: languages
){
1913 languageSubQuery
.add(descriptionElementQueryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString(), false), Occur
.SHOULD
);
1915 ((BooleanQuery
) nameQuery
).add(descriptionElementQueryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
1916 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1918 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1921 // text field from TextData
1922 textQuery
.add(descriptionElementQueryFactory
.newMultilanguageTextQuery("text", queryString
, languages
), Occur
.SHOULD
);
1924 // --- TermBase fields - by representation ----
1925 // state field from CategoricalData
1926 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("states.state", queryString
, languages
), Occur
.SHOULD
);
1928 // state field from CategoricalData
1929 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("states.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1931 // area field from Distribution
1932 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("area", queryString
, languages
), Occur
.SHOULD
);
1934 // status field from Distribution
1935 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("status", queryString
, languages
), Occur
.SHOULD
);
1937 finalQuery
.add(textQuery
, Occur
.MUST
);
1938 // --- classification ----
1940 if(classification
!= null){
1941 finalQuery
.add(descriptionElementQueryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
1944 // --- IdentifieableEntity fields - by uuid
1945 if(features
!= null && features
.size() > 0 ){
1946 finalQuery
.add(descriptionElementQueryFactory
.newEntityUuidsQuery("feature.uuid", features
), Occur
.MUST
);
1949 // the description must be associated with a taxon
1950 finalQuery
.add(descriptionElementQueryFactory
.newIsNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
1952 logger
.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery
.toString());
1957 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1958 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1959 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1961 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1962 * or {@link MultilanguageTextFieldBridge }
1963 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1964 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1965 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1967 * TODO move to utiliy class !!!!!!!!
1969 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1971 if(stringBuilder
== null){
1972 stringBuilder
= new StringBuilder();
1974 if(languages
== null || languages
.size() == 0){
1975 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
1977 for(Language lang
: languages
){
1978 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
1981 return stringBuilder
;
1985 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1986 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1987 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1989 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1992 UUID nameUuid
= taxon
.getName().getUuid();
1993 ZoologicalName taxonName
= getZoologicalName(nameUuid
, zooHashMap
);
1994 String epithetOfTaxon
= null;
1995 String infragenericEpithetOfTaxon
= null;
1996 String infraspecificEpithetOfTaxon
= null;
1997 if (taxonName
.isSpecies()){
1998 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1999 } else if (taxonName
.isInfraGeneric()){
2000 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
2001 } else if (taxonName
.isInfraSpecific()){
2002 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
2004 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
2005 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
2006 List
<String
> taxonNames
= new ArrayList
<String
>();
2008 for (TaxonNode node
: nodes
){
2009 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
2010 // List<String> synonymsEpithet = new ArrayList<String>();
2012 if (node
.getClassification().equals(classification
)){
2013 if (!node
.isTopmostNode()){
2014 TaxonNode parent
= node
.getParent();
2015 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
2016 TaxonNameBase
<?
,?
> parentName
= parent
.getTaxon().getName();
2017 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
2018 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
2019 Rank rankOfTaxon
= taxonName
.getRank();
2022 //create inferred synonyms for species, subspecies
2023 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
2025 Synonym inferredEpithet
= null;
2026 Synonym inferredGenus
= null;
2027 Synonym potentialCombination
= null;
2029 List
<String
> propertyPaths
= new ArrayList
<String
>();
2030 propertyPaths
.add("synonym");
2031 propertyPaths
.add("synonym.name");
2032 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
2033 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
2035 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2036 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2038 List
<TaxonRelationship
> taxonRelListParent
= null;
2039 List
<TaxonRelationship
> taxonRelListTaxon
= null;
2040 if (doWithMisappliedNames
){
2041 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2042 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2046 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
2049 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2050 Synonym syn
= synonymRelationOfParent
.getSynonym();
2052 inferredEpithet
= createInferredEpithets(taxon
,
2053 zooHashMap
, taxonName
, epithetOfTaxon
,
2054 infragenericEpithetOfTaxon
,
2055 infraspecificEpithetOfTaxon
,
2056 taxonNames
, parentName
,
2060 inferredSynonyms
.add(inferredEpithet
);
2061 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2062 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2065 if (doWithMisappliedNames
){
2067 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
2068 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2070 inferredEpithet
= createInferredEpithets(taxon
,
2071 zooHashMap
, taxonName
, epithetOfTaxon
,
2072 infragenericEpithetOfTaxon
,
2073 infraspecificEpithetOfTaxon
,
2074 taxonNames
, parentName
,
2077 inferredSynonyms
.add(inferredEpithet
);
2078 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2079 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2083 if (!taxonNames
.isEmpty()){
2084 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2085 ZoologicalName name
;
2086 if (!synNotInCDM
.isEmpty()){
2087 inferredSynonymsToBeRemoved
.clear();
2089 for (Synonym syn
:inferredSynonyms
){
2090 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2091 if (!synNotInCDM
.contains(name
.getNameCache())){
2092 inferredSynonymsToBeRemoved
.add(syn
);
2096 // Remove identified Synonyms from inferredSynonyms
2097 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2098 inferredSynonyms
.remove(synonym
);
2103 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
2106 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2107 TaxonNameBase synName
;
2108 ZoologicalName inferredSynName
;
2110 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2111 inferredGenus
= createInferredGenus(taxon
,
2112 zooHashMap
, taxonName
, epithetOfTaxon
,
2113 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
2115 inferredSynonyms
.add(inferredGenus
);
2116 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2117 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2122 if (doWithMisappliedNames
){
2124 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2125 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2126 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
2128 inferredSynonyms
.add(inferredGenus
);
2129 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2130 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2135 if (!taxonNames
.isEmpty()){
2136 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2137 ZoologicalName name
;
2138 if (!synNotInCDM
.isEmpty()){
2139 inferredSynonymsToBeRemoved
.clear();
2141 for (Synonym syn
:inferredSynonyms
){
2142 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2143 if (!synNotInCDM
.contains(name
.getNameCache())){
2144 inferredSynonymsToBeRemoved
.add(syn
);
2148 // Remove identified Synonyms from inferredSynonyms
2149 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2150 inferredSynonyms
.remove(synonym
);
2155 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
2157 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
2158 ZoologicalName inferredSynName
;
2159 //for all synonyms of the parent...
2160 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2161 TaxonNameBase synName
;
2162 Synonym synParent
= synonymRelationOfParent
.getSynonym();
2163 synName
= synParent
.getName();
2165 HibernateProxyHelper
.deproxy(synParent
);
2167 // Set the sourceReference
2168 sourceReference
= synParent
.getSec();
2170 // Determine the idInSource
2171 String idInSourceParent
= getIdInSource(synParent
);
2173 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2174 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2175 String synParentInfragenericName
= null;
2176 String synParentSpecificEpithet
= null;
2178 if (parentSynZooName
.isInfraGeneric()){
2179 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2181 if (parentSynZooName
.isSpecies()){
2182 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2185 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2186 synonymsGenus.put(synGenusName, idInSource);
2189 //for all synonyms of the taxon
2191 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2193 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2194 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2195 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
2197 synParentInfragenericName
,
2198 synParentSpecificEpithet
, syn
, zooHashMap
);
2200 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2201 inferredSynonyms
.add(potentialCombination
);
2202 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2203 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2210 if (doWithMisappliedNames
){
2212 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
2214 TaxonNameBase misappliedParentName
;
2216 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
2217 misappliedParentName
= misappliedParent
.getName();
2219 HibernateProxyHelper
.deproxy(misappliedParent
);
2221 // Set the sourceReference
2222 sourceReference
= misappliedParent
.getSec();
2224 // Determine the idInSource
2225 String idInSourceParent
= getIdInSource(misappliedParent
);
2227 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
2228 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2229 String synParentInfragenericName
= null;
2230 String synParentSpecificEpithet
= null;
2232 if (parentSynZooName
.isInfraGeneric()){
2233 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2235 if (parentSynZooName
.isSpecies()){
2236 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2240 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2241 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2242 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
2243 potentialCombination
= createPotentialCombination(
2244 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
2246 synParentInfragenericName
,
2247 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
2250 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2251 inferredSynonyms
.add(potentialCombination
);
2252 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2253 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2258 if (!taxonNames
.isEmpty()){
2259 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2260 ZoologicalName name
;
2261 if (!synNotInCDM
.isEmpty()){
2262 inferredSynonymsToBeRemoved
.clear();
2263 for (Synonym syn
:inferredSynonyms
){
2265 name
= (ZoologicalName
) syn
.getName();
2266 }catch (ClassCastException e
){
2267 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2269 if (!synNotInCDM
.contains(name
.getNameCache())){
2270 inferredSynonymsToBeRemoved
.add(syn
);
2273 // Remove identified Synonyms from inferredSynonyms
2274 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2275 inferredSynonyms
.remove(synonym
);
2281 logger
.info("The synonymrelationship type is not defined.");
2282 return inferredSynonyms
;
2289 return inferredSynonyms
;
2292 private Synonym
createPotentialCombination(String idInSourceParent
,
2293 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
2294 String synParentInfragenericName
, String synParentSpecificEpithet
,
2295 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2296 Synonym potentialCombination
;
2297 Reference sourceReference
;
2298 ZoologicalName inferredSynName
;
2299 HibernateProxyHelper
.deproxy(syn
);
2301 // Set sourceReference
2302 sourceReference
= syn
.getSec();
2303 if (sourceReference
== null){
2304 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2306 if (!parentSynZooName
.getTaxa().isEmpty()){
2307 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
2309 sourceReference
= taxon
.getSec();
2312 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
2314 String synTaxonInfraSpecificName
= null;
2316 if (parentSynZooName
.isSpecies()){
2317 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
2320 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
2321 synonymsEpithet.add(epithetName);
2324 //create potential combinations...
2325 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
2327 inferredSynName
.setGenusOrUninomial(synParentGenus
);
2328 if (zooSynName
.isSpecies()){
2329 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
2330 if (parentSynZooName
.isInfraGeneric()){
2331 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2334 if (zooSynName
.isInfraSpecific()){
2335 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
2336 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
2338 if (parentSynZooName
.isInfraGeneric()){
2339 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2343 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
2345 // Set the sourceReference
2346 potentialCombination
.setSec(sourceReference
);
2349 // Determine the idInSource
2350 String idInSourceSyn
= getIdInSource(syn
);
2352 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
2353 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2354 inferredSynName
.addSource(originalSource
);
2355 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2356 potentialCombination
.addSource(originalSource
);
2359 inferredSynName
.generateTitle();
2361 return potentialCombination
;
2364 private Synonym
createInferredGenus(Taxon taxon
,
2365 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2366 String epithetOfTaxon
, String genusOfTaxon
,
2367 List
<String
> taxonNames
, ZoologicalName zooParentName
,
2370 Synonym inferredGenus
;
2371 TaxonNameBase synName
;
2372 ZoologicalName inferredSynName
;
2373 synName
=syn
.getName();
2374 HibernateProxyHelper
.deproxy(syn
);
2376 // Determine the idInSource
2377 String idInSourceSyn
= getIdInSource(syn
);
2378 String idInSourceTaxon
= getIdInSource(taxon
);
2379 // Determine the sourceReference
2380 Reference sourceReference
= syn
.getSec();
2382 //logger.warn(sourceReference.getTitleCache());
2384 synName
= syn
.getName();
2385 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2386 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
2387 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
2388 synonymsEpithet.add(synSpeciesEpithetName);
2391 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2392 //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...
2395 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
2396 if (zooParentName
.isInfraGeneric()){
2397 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
2400 if (taxonName
.isSpecies()){
2401 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
2403 if (taxonName
.isInfraSpecific()){
2404 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2405 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
2409 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
2411 // Set the sourceReference
2412 inferredGenus
.setSec(sourceReference
);
2414 // Add the original source
2415 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
2416 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2417 inferredGenus
.addSource(originalSource
);
2419 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2420 inferredSynName
.addSource(originalSource
);
2421 originalSource
= null;
2424 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
2425 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2426 inferredGenus
.addSource(originalSource
);
2428 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2429 inferredSynName
.addSource(originalSource
);
2430 originalSource
= null;
2433 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
2435 inferredSynName
.generateTitle();
2438 return inferredGenus
;
2441 private Synonym
createInferredEpithets(Taxon taxon
,
2442 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2443 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
2444 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
2445 TaxonNameBase parentName
, TaxonBase syn
) {
2447 Synonym inferredEpithet
;
2448 TaxonNameBase
<?
,?
> synName
;
2449 ZoologicalName inferredSynName
;
2450 HibernateProxyHelper
.deproxy(syn
);
2452 // Determine the idInSource
2453 String idInSourceSyn
= getIdInSource(syn
);
2454 String idInSourceTaxon
= getIdInSource(taxon
);
2455 // Determine the sourceReference
2456 Reference
<?
> sourceReference
= syn
.getSec();
2458 if (sourceReference
== null){
2459 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
2460 sourceReference
= taxon
.getSec();
2463 synName
= syn
.getName();
2464 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2465 String synGenusName
= zooSynName
.getGenusOrUninomial();
2466 String synInfraGenericEpithet
= null;
2467 String synSpecificEpithet
= null;
2469 if (zooSynName
.getInfraGenericEpithet() != null){
2470 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
2473 if (zooSynName
.isInfraSpecific()){
2474 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
2477 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2478 synonymsGenus.put(synGenusName, idInSource);
2481 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2483 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
2484 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
2485 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
2487 inferredSynName
.setGenusOrUninomial(synGenusName
);
2489 if (parentName
.isInfraGeneric()){
2490 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
2492 if (taxonName
.isSpecies()){
2493 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2494 }else if (taxonName
.isInfraSpecific()){
2495 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
2496 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
2499 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
2501 // Set the sourceReference
2502 inferredEpithet
.setSec(sourceReference
);
2504 /* Add the original source
2505 if (idInSource != null) {
2506 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
2509 Reference citation = getCitation(syn);
2510 if (citation != null) {
2511 originalSource.setCitation(citation);
2512 inferredEpithet.addSource(originalSource);
2515 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
2518 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2520 inferredEpithet
.addSource(originalSource
);
2522 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2524 inferredSynName
.addSource(originalSource
);
2528 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
2530 inferredSynName
.generateTitle();
2531 return inferredEpithet
;
2535 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
2536 * Very likely only useful for createInferredSynonyms().
2541 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2542 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
2543 if (taxonName
== null) {
2544 taxonName
= zooHashMap
.get(uuid
);
2550 * Returns the idInSource for a given Synonym.
2553 private String
getIdInSource(TaxonBase taxonBase
) {
2554 String idInSource
= null;
2555 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
2556 if (sources
.size() == 1) {
2557 IdentifiableSource source
= sources
.iterator().next();
2558 if (source
!= null) {
2559 idInSource
= source
.getIdInSource();
2561 } else if (sources
.size() > 1) {
2564 for (IdentifiableSource source
: sources
) {
2565 idInSource
+= source
.getIdInSource();
2566 if (count
< sources
.size()) {
2571 } else if (sources
.size() == 0){
2572 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
2581 * Returns the citation for a given Synonym.
2584 private Reference
getCitation(Synonym syn
) {
2585 Reference citation
= null;
2586 Set
<IdentifiableSource
> sources
= syn
.getSources();
2587 if (sources
.size() == 1) {
2588 IdentifiableSource source
= sources
.iterator().next();
2589 if (source
!= null) {
2590 citation
= source
.getCitation();
2592 } else if (sources
.size() > 1) {
2593 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
2600 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
2601 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2603 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
2604 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
2605 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
2607 return inferredSynonyms
;
2611 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listClassifications(eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)
2614 public List
<Classification
> listClassifications(TaxonBase taxonBase
, Integer limit
, Integer start
, List
<String
> propertyPaths
) {
2616 // TODO quickly implemented, create according dao !!!!
2617 Set
<TaxonNode
> nodes
= new HashSet
<TaxonNode
>();
2618 Set
<Classification
> classifications
= new HashSet
<Classification
>();
2619 List
<Classification
> list
= new ArrayList
<Classification
>();
2621 if (taxonBase
== null) {
2625 taxonBase
= load(taxonBase
.getUuid());
2627 if (taxonBase
instanceof Taxon
) {
2628 nodes
.addAll(((Taxon
)taxonBase
).getTaxonNodes());
2630 for (Taxon taxon
: ((Synonym
)taxonBase
).getAcceptedTaxa() ) {
2631 nodes
.addAll(taxon
.getTaxonNodes());
2634 for (TaxonNode node
: nodes
) {
2635 classifications
.add(node
.getClassification());
2637 list
.addAll(classifications
);