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
.Iterator
;
19 import java
.util
.List
;
22 import java
.util
.UUID
;
24 import javax
.persistence
.EntityNotFoundException
;
26 import org
.apache
.log4j
.Logger
;
27 import org
.apache
.lucene
.index
.CorruptIndexException
;
28 import org
.apache
.lucene
.queryParser
.ParseException
;
29 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
30 import org
.apache
.lucene
.search
.BooleanFilter
;
31 import org
.apache
.lucene
.search
.BooleanQuery
;
32 import org
.apache
.lucene
.search
.DocIdSet
;
33 import org
.apache
.lucene
.search
.Query
;
34 import org
.apache
.lucene
.search
.QueryWrapperFilter
;
35 import org
.apache
.lucene
.search
.SortField
;
36 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
37 import org
.springframework
.stereotype
.Service
;
38 import org
.springframework
.transaction
.annotation
.Transactional
;
40 import eu
.etaxonomy
.cdm
.api
.service
.config
.DeleteConfiguratorBase
;
41 import eu
.etaxonomy
.cdm
.api
.service
.config
.IFindTaxaAndNamesConfigurator
;
42 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
43 import eu
.etaxonomy
.cdm
.api
.service
.config
.SynonymDeletionConfigurator
;
44 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
45 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonNodeDeletionConfigurator
.ChildHandling
;
46 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
47 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
48 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
49 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
50 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
51 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
52 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
53 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearch
;
54 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearchException
;
55 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
56 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
.TopGroupsWithMaxScore
;
57 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
58 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
59 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
60 import eu
.etaxonomy
.cdm
.api
.service
.util
.TaxonRelationshipEdge
;
61 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
62 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
63 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
64 import eu
.etaxonomy
.cdm
.hibernate
.search
.GroupByTaxonClassBridge
;
65 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
66 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
67 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
68 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
69 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
70 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
71 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
72 import eu
.etaxonomy
.cdm
.model
.common
.OriginalSourceType
;
73 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
74 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
75 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
76 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
77 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
78 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
79 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
80 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
81 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
82 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
83 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTermBase
;
84 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
85 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
86 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
87 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
88 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
89 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
90 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
91 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
92 import eu
.etaxonomy
.cdm
.model
.molecular
.Amplification
;
93 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
94 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
95 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
96 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
97 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
98 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
99 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
100 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
101 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
102 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
103 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
104 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
105 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
106 import eu
.etaxonomy
.cdm
.model
.taxon
.ITaxonTreeNode
;
107 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
108 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
109 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
110 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
111 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
112 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
113 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
114 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
115 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
116 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
117 import eu
.etaxonomy
.cdm
.persistence
.dao
.initializer
.AbstractBeanInitializer
;
118 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
119 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
120 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.IClassificationDao
;
121 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
122 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
123 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
124 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
125 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
126 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
130 * @author a.kohlbecker
135 @Transactional(readOnly
= true)
136 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
137 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
139 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
141 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
143 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
147 private ITaxonNameDao nameDao
;
150 private INameService nameService
;
153 private ITaxonNodeService nodeService
;
156 private ICdmGenericDao genericDao
;
159 private IDescriptionService descriptionService
;
162 private IOrderedTermVocabularyDao orderedVocabularyDao
;
165 private IOccurrenceDao occurrenceDao
;
168 private IClassificationDao classificationDao
;
171 private AbstractBeanInitializer beanInitializer
;
174 private ILuceneIndexToolProvider luceneIndexToolProvider
;
179 public TaxonServiceImpl(){
180 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
184 * FIXME Candidate for harmonization
185 * rename searchByName ?
188 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
189 return dao
.getTaxaByName(name
, sec
);
193 * FIXME Candidate for harmonization
194 * list(Synonym.class, ...)
196 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
199 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
200 return dao
.getAllSynonyms(limit
, start
);
204 * FIXME Candidate for harmonization
205 * list(Taxon.class, ...)
207 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
210 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
211 return dao
.getAllTaxa(limit
, start
);
215 * FIXME Candidate for harmonization
216 * merge with getRootTaxa(Reference sec, ..., ...)
218 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
221 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
222 if (cdmFetch
== null){
223 cdmFetch
= CdmFetch
.NO_FETCH();
225 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
230 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
233 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
234 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
238 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
241 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
242 return dao
.getAllRelationships(limit
, start
);
246 * FIXME Candidate for harmonization
247 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
251 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
253 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
254 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
255 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
256 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
257 return taxonRelTypeVocabulary
;
264 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
267 @Transactional(readOnly
= false)
268 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
270 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
271 synonymName
.removeTaxonBase(synonym
);
272 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
273 taxonName
.removeTaxonBase(acceptedTaxon
);
275 synonym
.setName(taxonName
);
276 acceptedTaxon
.setName(synonymName
);
278 // the accepted taxon needs a new uuid because the concept has changed
279 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
280 //acceptedTaxon.setUuid(UUID.randomUUID());
285 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
289 @Transactional(readOnly
= false)
290 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
292 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
293 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
294 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
296 //check synonym is not homotypic
297 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
298 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
299 throw new HomotypicalGroupChangeException(message
);
302 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
304 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
305 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
306 Set
<NameRelationship
> basionymsAndReplacedSynonyms
= synonymHomotypicGroup
.getBasionymAndReplacedSynonymRelations();
308 for (Synonym heteroSynonym
: heteroSynonyms
){
309 if (synonym
.equals(heteroSynonym
)){
310 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
313 //move synonyms in same homotypic group to new accepted taxon
314 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
318 //synonym.getName().removeTaxonBase(synonym);
321 // deleteSynonym(synonym, taxon, false);
324 SynonymDeletionConfigurator config
= new SynonymDeletionConfigurator();
325 config
.setDeleteNameIfPossible(false);
326 this.deleteSynonym(synonym
, acceptedTaxon
, config
);
328 } catch (Exception e
) {
329 logger
.info("Can't delete old synonym from database");
333 return newAcceptedTaxon
;
338 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
340 // Get name from synonym
341 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
343 /* // remove synonym from taxon
344 toTaxon.removeSynonym(synonym);
346 // Create a taxon with synonym name
347 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
349 // Add taxon relation
350 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
352 // since we are swapping names, we have to detach the name from the synonym completely.
353 // Otherwise the synonym will still be in the list of typified names.
354 // synonym.getName().removeTaxonBase(synonym);
355 this.deleteSynonym(synonym
, null);
362 * @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)
364 @Transactional(readOnly
= false)
366 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
367 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
369 TaxonNameBase synonymName
= synonym
.getName();
370 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
374 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
375 newHomotypicalGroup
.addTypifiedName(synonymName
);
377 //remove existing basionym relationships
378 synonymName
.removeBasionyms();
380 //add basionym relationship
381 if (setBasionymRelationIfApplicable
){
382 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
383 for (TaxonNameBase basionym
: basionyms
){
384 synonymName
.addBasionym(basionym
);
388 //set synonym relationship correctly
389 // SynonymRelationship relToTaxon = null;
390 boolean relToTargetTaxonExists
= false;
391 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
392 for (SynonymRelationship rel
: existingRelations
){
393 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
394 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
395 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
396 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
397 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
398 rel
.setType(newRelationType
);
399 //TODO handle citation and microCitation
402 relToTargetTaxonExists
= true;
404 if (removeFromOtherTaxa
){
405 acceptedTaxon
.removeSynonym(synonym
, false);
411 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
412 Taxon acceptedTaxon
= targetTaxon
;
413 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
414 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
415 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
416 //TODO handle citation and microCitation
417 Reference citation
= null;
418 String microCitation
= null;
419 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
426 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
429 @Transactional(readOnly
= false)
430 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
432 clazz
= TaxonBase
.class;
434 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
439 protected void setDao(ITaxonDao dao
) {
444 * @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)
447 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
448 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
450 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
451 if(numberOfResults
> 0) { // no point checking again
452 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
455 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
459 * @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)
462 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
463 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
465 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
466 if(numberOfResults
> 0) { // no point checking again
467 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
474 * @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)
477 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
478 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
480 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
481 if(numberOfResults
> 0) { // no point checking again
482 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
488 * @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)
491 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
492 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
494 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
495 if(numberOfResults
> 0) { // no point checking again
496 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
498 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
502 * @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)
505 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
506 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
508 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
509 if(numberOfResults
> 0) { // no point checking again
510 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
516 * @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)
519 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
520 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
522 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
523 if(numberOfResults
> 0) { // no point checking again
524 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
526 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
530 public List
<Taxon
> listAcceptedTaxaFor(UUID synonymUuid
, UUID classificationUuid
, Integer pageSize
, Integer pageNumber
,
531 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
532 return pageAcceptedTaxaFor(synonymUuid
, classificationUuid
, pageSize
, pageNumber
, orderHints
, propertyPaths
).getRecords();
536 public Pager
<Taxon
> pageAcceptedTaxaFor(UUID synonymUuid
, UUID classificationUuid
, Integer pageSize
, Integer pageNumber
,
537 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
539 List
<Taxon
> list
= new ArrayList
<Taxon
>();
542 Synonym synonym
= null;
545 synonym
= (Synonym
) dao
.load(synonymUuid
);
546 } catch (ClassCastException e
){
547 throw new EntityNotFoundException("The TaxonBase entity referenced by " + synonymUuid
+ " is not a Synonmy");
548 } catch (NullPointerException e
){
549 throw new EntityNotFoundException("No TaxonBase entity found for " + synonymUuid
);
552 Classification classificationFilter
= null;
553 if(classificationUuid
!= null){
555 classificationFilter
= classificationDao
.load(classificationUuid
);
556 } catch (NullPointerException e
){
557 throw new EntityNotFoundException("No Classification entity found for " + classificationUuid
);
559 if(classificationFilter
== null){
564 count
= dao
.countAcceptedTaxaFor(synonym
, classificationFilter
) ;
565 if(count
> (pageSize
* pageNumber
)){
566 list
= dao
.listAcceptedTaxaFor(synonym
, classificationFilter
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
569 return new DefaultPagerImpl
<Taxon
>(pageNumber
, count
.intValue(), pageSize
, list
);
575 * @param includeRelationships
579 * @param propertyPaths
580 * @return an List which is not specifically ordered
583 public Set
<Taxon
> listRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Integer maxDepth
,
584 Integer limit
, Integer start
, List
<String
> propertyPaths
) {
586 Set
<Taxon
> relatedTaxa
= collectRelatedTaxa(taxon
, includeRelationships
, new HashSet
<Taxon
>(), maxDepth
);
587 relatedTaxa
.remove(taxon
);
588 beanInitializer
.initializeAll(relatedTaxa
, propertyPaths
);
594 * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the
595 * <code>taxon</code> supplied as parameter.
598 * @param includeRelationships
600 * @param maxDepth can be <code>null</code> for infinite depth
603 private Set
<Taxon
> collectRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Set
<Taxon
> taxa
, Integer maxDepth
) {
609 if(includeRelationships
.isEmpty()){
613 if(maxDepth
!= null) {
616 if(logger
.isDebugEnabled()){
617 logger
.debug("collecting related taxa for " + taxon
+ " with maxDepth=" + maxDepth
);
619 List
<TaxonRelationship
> taxonRelationships
= dao
.getTaxonRelationships(taxon
, null, null, null, null, null, null);
620 for (TaxonRelationship taxRel
: taxonRelationships
) {
623 if (taxRel
.getToTaxon() == null || taxRel
.getFromTaxon() == null || taxRel
.getType() == null) {
626 // filter by includeRelationships
627 for (TaxonRelationshipEdge relationshipEdgeFilter
: includeRelationships
) {
628 if ( relationshipEdgeFilter
.getTaxonRelationshipType().equals(taxRel
.getType()) ) {
629 if (relationshipEdgeFilter
.getDirections().contains(Direction
.relatedTo
) && !taxa
.contains(taxRel
.getToTaxon())) {
630 if(logger
.isDebugEnabled()){
631 logger
.debug(maxDepth
+ ": " + taxon
.getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxRel
.getToTaxon().getTitleCache());
633 taxa
.add(taxRel
.getToTaxon());
634 if(maxDepth
== null || maxDepth
> 0) {
635 taxa
.addAll(collectRelatedTaxa(taxRel
.getToTaxon(), includeRelationships
, taxa
, maxDepth
));
638 if(relationshipEdgeFilter
.getDirections().contains(Direction
.relatedFrom
) && !taxa
.contains(taxRel
.getFromTaxon())) {
639 taxa
.add(taxRel
.getFromTaxon());
640 if(logger
.isDebugEnabled()){
641 logger
.debug(maxDepth
+ ": " +taxRel
.getFromTaxon().getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxon
.getTitleCache() );
643 if(maxDepth
== null || maxDepth
> 0) {
644 taxa
.addAll(collectRelatedTaxa(taxRel
.getFromTaxon(), includeRelationships
, taxa
, maxDepth
));
654 * @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)
657 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
658 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
660 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
661 if(numberOfResults
> 0) { // no point checking again
662 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
665 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
669 * @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)
672 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
673 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
675 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
676 if(numberOfResults
> 0) { // no point checking again
677 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
680 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
684 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
687 public List
<List
<Synonym
>> getSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
688 List
<List
<Synonym
>> result
= new ArrayList
<List
<Synonym
>>();
689 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
692 result
.add(t
.getHomotypicSynonymsByHomotypicGroup());
695 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
696 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
697 result
.add(t
.getSynonymsInGroup(homotypicalGroup
));
705 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
708 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
709 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
710 return t
.getHomotypicSynonymsByHomotypicGroup();
714 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
717 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
718 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
719 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
720 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
721 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
722 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
724 return heterotypicSynonymyGroups
;
728 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
730 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
731 // Class<? extends TaxonBase> clazz = null;
732 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
733 // clazz = TaxonBase.class;
734 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
735 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
736 // } else if(configurator.isDoTaxa()) {
737 // clazz = Taxon.class;
738 // //propertyPath = configurator.getTaxonPropertyPath();
739 // } else if (configurator.isDoSynonyms()) {
740 // clazz = Synonym.class;
741 // //propertyPath = configurator.getSynonymPropertyPath();
745 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
750 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
753 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
755 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
756 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
757 List
<TaxonBase
> taxa
= null;
760 long numberTaxaResults
= 0L;
763 List
<String
> propertyPath
= new ArrayList
<String
>();
764 if(configurator
.getTaxonPropertyPath() != null){
765 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
769 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
770 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
772 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
773 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
774 configurator
.getNamedAreas());
777 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
778 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
779 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
780 configurator
.getMatchMode(), configurator
.getNamedAreas(),
781 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
785 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
788 results
.addAll(taxa
);
791 numberOfResults
+= numberTaxaResults
;
793 // Names without taxa
794 if (configurator
.isDoNamesWithoutTaxa()) {
795 int numberNameResults
= 0;
797 List
<?
extends TaxonNameBase
<?
,?
>> names
=
798 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
799 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
800 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
801 if (names
.size() > 0) {
802 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
803 if (taxonName
.getTaxonBases().size() == 0) {
804 results
.add(taxonName
);
808 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
809 numberOfResults
+= numberNameResults
;
813 // Taxa from common names
815 if (configurator
.isDoTaxaByCommonNames()) {
816 taxa
= new ArrayList
<TaxonBase
>();
817 numberTaxaResults
= 0;
818 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
819 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
821 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
822 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
823 for( Object
[] entry
: commonNameResults
) {
824 taxa
.add((TaxonBase
) entry
[0]);
828 results
.addAll(taxa
);
830 numberOfResults
+= numberTaxaResults
;
834 return new DefaultPagerImpl
<IdentifiableEntity
>
835 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
838 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
839 return dao
.getUuidAndTitleCache();
843 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
846 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
847 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
848 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
849 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
850 for (TaxonDescription taxDesc
: descriptions
){
851 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
852 for (DescriptionElementBase descElem
: elements
){
853 for(Media media
: descElem
.getMedia()){
855 //find the best matching representation
856 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
865 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
868 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, boolean limitToGalleries
, List
<String
> propertyPath
){
869 return listMedia(taxon
, includeRelationships
, limitToGalleries
, true, false, false, propertyPath
);
874 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)
877 public List
<Media
> listMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
878 Boolean limitToGalleries
, Boolean includeTaxonDescriptions
, Boolean includeOccurrences
,
879 Boolean includeTaxonNameDescriptions
, List
<String
> propertyPath
) {
881 logger
.trace("listMedia() - START");
883 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
884 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
886 if (limitToGalleries
== null) {
887 limitToGalleries
= false;
890 // --- resolve related taxa
891 if (includeRelationships
!= null && ! includeRelationships
.isEmpty()) {
892 logger
.trace("listMedia() - resolve related taxa");
893 taxa
= listRelatedTaxa(taxon
, includeRelationships
, null, null, null, null);
896 taxa
.add((Taxon
) dao
.load(taxon
.getUuid()));
898 if(includeTaxonDescriptions
!= null && includeTaxonDescriptions
){
899 logger
.trace("listMedia() - includeTaxonDescriptions");
900 List
<TaxonDescription
> taxonDescriptions
= new ArrayList
<TaxonDescription
>();
901 // --- TaxonDescriptions
902 for (Taxon t
: taxa
) {
903 taxonDescriptions
.addAll(descriptionService
.listTaxonDescriptions(t
, null, null, null, null, propertyPath
));
905 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
906 if (!limitToGalleries
|| taxonDescription
.isImageGallery()) {
907 for (DescriptionElementBase element
: taxonDescription
.getElements()) {
908 for (Media media
: element
.getMedia()) {
909 taxonMedia
.add(media
);
917 if(includeOccurrences
!= null && includeOccurrences
) {
918 logger
.trace("listMedia() - includeOccurrences");
919 Set
<SpecimenOrObservationBase
> specimensOrObservations
= new HashSet
<SpecimenOrObservationBase
>();
921 for (Taxon t
: taxa
) {
922 specimensOrObservations
.addAll(occurrenceDao
.listByAssociatedTaxon(null, t
, null, null, null, null));
924 for (SpecimenOrObservationBase occurrence
: specimensOrObservations
) {
926 // direct media removed from specimen #3597
927 // taxonMedia.addAll(occurrence.getMedia());
929 // SpecimenDescriptions
930 Set
<SpecimenDescription
> specimenDescriptions
= occurrence
.getSpecimenDescriptions();
931 for (DescriptionBase specimenDescription
: specimenDescriptions
) {
932 if (!limitToGalleries
|| specimenDescription
.isImageGallery()) {
933 Set
<DescriptionElementBase
> elements
= specimenDescription
.getElements();
934 for (DescriptionElementBase element
: elements
) {
935 for (Media media
: element
.getMedia()) {
936 taxonMedia
.add(media
);
943 //TODO why may collections have media attached? #
944 if (occurrence
.isInstanceOf(DerivedUnit
.class)) {
945 DerivedUnit derivedUnit
= CdmBase
.deproxy(occurrence
, DerivedUnit
.class);
946 if (derivedUnit
.getCollection() != null){
947 taxonMedia
.addAll(derivedUnit
.getCollection().getMedia());
951 // pherograms & gelPhotos
952 if (occurrence
.isInstanceOf(DnaSample
.class)) {
953 DnaSample dnaSample
= CdmBase
.deproxy(occurrence
, DnaSample
.class);
954 Set
<Sequence
> sequences
= dnaSample
.getSequences();
955 //we do show only those gelPhotos which lead to a consensus sequence
956 for (Sequence sequence
: sequences
) {
957 Set
<Media
> dnaRelatedMedia
= new HashSet
<Media
>();
958 for (SingleRead singleRead
: sequence
.getSingleReads()){
959 Amplification amplification
= singleRead
.getAmplification();
960 dnaRelatedMedia
.add(amplification
.getGelPhoto());
961 dnaRelatedMedia
.add(singleRead
.getPherogram());
962 dnaRelatedMedia
.remove(null);
964 taxonMedia
.addAll(dnaRelatedMedia
);
971 if(includeTaxonNameDescriptions
!= null && includeTaxonNameDescriptions
) {
972 logger
.trace("listMedia() - includeTaxonNameDescriptions");
973 // --- TaxonNameDescription
974 Set
<TaxonNameDescription
> nameDescriptions
= new HashSet
<TaxonNameDescription
>();
975 for (Taxon t
: taxa
) {
976 nameDescriptions
.addAll(t
.getName().getDescriptions());
978 for(TaxonNameDescription nameDescription
: nameDescriptions
){
979 if (!limitToGalleries
|| nameDescription
.isImageGallery()) {
980 Set
<DescriptionElementBase
> elements
= nameDescription
.getElements();
981 for (DescriptionElementBase element
: elements
) {
982 for (Media media
: element
.getMedia()) {
983 taxonMedia
.add(media
);
991 logger
.trace("listMedia() - initialize");
992 beanInitializer
.initializeAll(taxonMedia
, propertyPath
);
994 logger
.trace("listMedia() - END");
1000 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
1003 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
1004 return this.dao
.listByIds(listOfIDs
, null, null, null, null);
1008 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
1011 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
1012 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
1016 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
1019 public int countAllRelationships() {
1020 return this.dao
.countAllRelationships();
1027 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
1030 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
1031 return this.dao
.findIdenticalTaxonNames(propertyPath
);
1036 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
1039 public String
deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
, Classification classification
) {
1040 if (config
== null){
1041 config
= new TaxonDeletionConfigurator();
1044 List
<String
> referencedObjects
= isDeletable(taxon
, config
);
1046 if (referencedObjects
.isEmpty()){
1047 // --- DeleteSynonymRelations
1048 if (config
.isDeleteSynonymRelations()){
1049 boolean removeSynonymNameFromHomotypicalGroup
= false;
1050 // use tmp Set to avoid concurrent modification
1051 Set
<SynonymRelationship
> synRelsToDelete
= new HashSet
<SynonymRelationship
>();
1052 synRelsToDelete
.addAll(taxon
.getSynonymRelations());
1053 for (SynonymRelationship synRel
: synRelsToDelete
){
1054 Synonym synonym
= synRel
.getSynonym();
1055 // taxon.removeSynonymRelation will set the accepted taxon and the synonym to NULL
1056 // this will cause hibernate to delete the relationship since
1057 // the SynonymRelationship field on both is annotated with removeOrphan
1058 // so no further explicit deleting of the relationship should be done here
1059 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
1061 // --- DeleteSynonymsIfPossible
1062 if (config
.isDeleteSynonymsIfPossible()){
1064 boolean newHomotypicGroupIfNeeded
= true;
1065 SynonymDeletionConfigurator synConfig
= new SynonymDeletionConfigurator();
1066 deleteSynonym(synonym
, taxon
, synConfig
);
1068 // relationship will be deleted by hibernate automatically,
1069 // see comment above and http://dev.e-taxonomy.eu/trac/ticket/3797
1071 // deleteSynonymRelationships(synonym, taxon);
1076 // --- DeleteTaxonRelationships
1077 if (! config
.isDeleteTaxonRelationships()){
1078 if (taxon
.getTaxonRelations().size() > 0){
1079 String message
= "Taxon can't be deleted as it is related to another taxon. " +
1080 "Remove taxon from all relations to other taxa prior to deletion.";
1081 // throw new ReferencedObjectUndeletableException(message);
1084 for (TaxonRelationship taxRel
: taxon
.getTaxonRelations()){
1085 if (config
.isDeleteMisappliedNamesAndInvalidDesignations()){
1086 if (taxRel
.getType().equals(TaxonRelationshipType
.MISAPPLIED_NAME_FOR()) || taxRel
.getType().equals(TaxonRelationshipType
.INVALID_DESIGNATION_FOR())){
1087 if (taxon
.equals(taxRel
.getToTaxon())){
1088 this.deleteTaxon(taxRel
.getFromTaxon(), config
, classification
);
1092 taxon
.removeTaxonRelation(taxRel
);
1093 /*if (taxFrom.equals(taxon)){
1095 this.deleteTaxon(taxTo, taxConf, classification);
1096 } catch(DataChangeNoRollbackException e){
1097 logger.debug("A related taxon will not be deleted." + e.getMessage());
1101 this.deleteTaxon(taxFrom, taxConf, classification);
1102 } catch(DataChangeNoRollbackException e){
1103 logger.debug("A related taxon will not be deleted." + e.getMessage());
1111 if (config
.isDeleteDescriptions()){
1112 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
1113 List
<TaxonDescription
> removeDescriptions
= new ArrayList
<TaxonDescription
>();
1114 for (TaxonDescription desc
: descriptions
){
1115 //TODO use description delete configurator ?
1116 //FIXME check if description is ALWAYS deletable
1117 if (desc
.getDescribedSpecimenOrObservation() != null){
1118 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
1119 " which also describes specimens or abservations";
1120 //throw new ReferencedObjectUndeletableException(message);
1122 removeDescriptions
.add(desc
);
1123 descriptionService
.delete(desc
);
1126 for (TaxonDescription desc
: removeDescriptions
){
1127 taxon
.removeDescription(desc
);
1132 /* //check references with only reverse mapping
1133 String message = checkForReferences(taxon);
1134 if (message != null){
1135 //throw new ReferencedObjectUndeletableException(message.toString());
1138 if (! config
.isDeleteTaxonNodes() || (!config
.isDeleteInAllClassifications() && classification
== null )){
1139 //if (taxon.getTaxonNodes().size() > 0){
1140 // message = "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion or define a classification where it should be deleted or adapt the taxon deletion configurator.";
1141 // throw new ReferencedObjectUndeletableException(message);
1144 if (taxon
.getTaxonNodes().size() != 0){
1145 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1146 Iterator
<TaxonNode
> iterator
= nodes
.iterator();
1147 TaxonNode node
= null;
1148 boolean deleteChildren
;
1149 if (config
.getTaxonNodeConfig().getChildHandling().equals(ChildHandling
.DELETE
)){
1150 deleteChildren
= true;
1152 deleteChildren
= false;
1154 boolean success
= true;
1155 if (!config
.isDeleteInAllClassifications() && !(classification
== null)){
1156 while (iterator
.hasNext()){
1157 node
= iterator
.next();
1158 if (node
.getClassification().equals(classification
)){
1164 success
=taxon
.removeTaxonNode(node
, deleteChildren
);
1165 nodeService
.delete(node
);
1167 // message = "Taxon is not used in defined classification";
1168 // throw new DataChangeNoRollbackException(message);
1170 } else if (config
.isDeleteInAllClassifications()){
1171 Set
<ITaxonTreeNode
> nodesList
= new HashSet
<ITaxonTreeNode
>();
1172 nodesList
.addAll(taxon
.getTaxonNodes());
1174 for (ITaxonTreeNode treeNode
: nodesList
){
1175 TaxonNode taxonNode
= (TaxonNode
) treeNode
;
1176 if(!deleteChildren
){
1177 /* Object[] childNodes = taxonNode.getChildNodes().toArray();
1178 //nodesList.addAll(taxonNode.getChildNodes());
1179 for (Object childNode: childNodes){
1180 TaxonNode childNodeCast = (TaxonNode) childNode;
1181 deleteTaxon(childNodeCast.getTaxon(), config, classification);
1185 /*for (TaxonNode childNode: taxonNode.getChildNodes()){
1186 deleteTaxon(childNode.getTaxon(), config, classification);
1189 // taxon.removeTaxonNode(taxonNode);
1190 //nodeService.delete(taxonNode);
1193 Object
[] childNodes
= taxonNode
.getChildNodes().toArray();
1194 for (Object childNode
: childNodes
){
1195 TaxonNode childNodeCast
= (TaxonNode
) childNode
;
1196 taxonNode
.getParent().addChildNode(childNodeCast
, childNodeCast
.getReference(), childNodeCast
.getMicroReference());
1199 //taxon.removeTaxonNode(taxonNode);
1202 config
.getTaxonNodeConfig().setDeleteTaxon(false);
1203 nodeService
.deleteTaxonNodes(nodesList
, config
);
1206 // message = "The taxon node could not be deleted.";
1207 //throw new DataChangeNoRollbackException(message);
1213 //PolytomousKey TODO
1215 boolean usedInPolytomousKey
= checkForPolytomousKeys(taxon
);
1217 if (config
.isDeleteNameIfPossible()){
1220 //TaxonNameBase name = nameService.find(taxon.getName().getUuid());
1221 TaxonNameBase name
= (TaxonNameBase
)HibernateProxyHelper
.deproxy(taxon
.getName());
1222 //check whether taxon will be deleted or not
1223 if ((taxon
.getTaxonNodes() == null || taxon
.getTaxonNodes().size()== 0) && name
!= null ){
1224 taxon
= (Taxon
) HibernateProxyHelper
.deproxy(taxon
);
1225 name
.removeTaxonBase(taxon
);
1226 nameService
.save(name
);
1227 String uuidString
= nameService
.delete(name
, config
.getNameDeletionConfig());
1228 logger
.debug(uuidString
);
1234 /* Set<TaxonDescription> descriptions = taxon.getDescriptions();
1236 for (TaxonDescription desc: descriptions){
1237 if (config.isDeleteDescriptions()){
1238 //TODO use description delete configurator ?
1239 //FIXME check if description is ALWAYS deletable
1240 taxon.removeDescription(desc);
1241 descriptionService.delete(desc);
1243 if (desc.getDescribedSpecimenOrObservations().size()>0){
1244 String message = "Taxon can't be deleted as it is used in a TaxonDescription" +
1245 " which also describes specimens or observations";
1246 throw new ReferencedObjectUndeletableException(message);
1251 if ((taxon
.getTaxonNodes() == null || taxon
.getTaxonNodes().size()== 0) ){
1252 UUID uuid
= dao
.delete(taxon
);
1253 return uuid
.toString();
1255 return "The Taxon can't be deleted.";
1258 return referencedObjects
.toString();
1264 private String
checkForReferences(Taxon taxon
){
1265 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
1266 for (CdmBase referencingObject
: referencingObjects
){
1267 //IIdentificationKeys (Media, Polytomous, MultiAccess)
1268 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
1269 String message
= "Taxon" + taxon
.getTitleCache() + "can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
1275 /* //PolytomousKeyNode
1276 if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){
1277 String message = "Taxon" + taxon.getTitleCache() + " can't be deleted as it is used in polytomous key node";
1282 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
1283 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
1288 if (referencingObject
.isInstanceOf(DeterminationEvent
.class)){
1289 String message
= "Taxon can't be deleted as it is used in a determination event";
1295 referencingObjects
= null;
1299 private boolean checkForPolytomousKeys(Taxon taxon
){
1300 boolean result
= false;
1301 List
<CdmBase
> list
= genericDao
.getCdmBasesByFieldAndClass(PolytomousKeyNode
.class, "taxon", taxon
);
1302 if (!list
.isEmpty()) {
1308 @Transactional(readOnly
= false)
1309 public UUID
delete(Synonym syn
){
1310 UUID result
= syn
.getUuid();
1311 this.deleteSynonym(syn
, null);
1316 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1318 @Transactional(readOnly
= false)
1320 public String
deleteSynonym(Synonym synonym
, SynonymDeletionConfigurator config
) {
1321 return deleteSynonym(synonym
, null, config
);
1327 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1329 @Transactional(readOnly
= false)
1331 public String
deleteSynonym(Synonym synonym
, Taxon taxon
, SynonymDeletionConfigurator config
) {
1332 if (synonym
== null){
1336 if (config
== null){
1337 config
= new SynonymDeletionConfigurator();
1339 List
<String
> messages
= isDeletable(synonym
, config
);
1340 if (messages
.isEmpty()){
1341 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
1343 //remove synonymRelationship
1344 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
1346 taxonSet
.add(taxon
);
1348 taxonSet
.addAll(synonym
.getAcceptedTaxa());
1350 for (Taxon relatedTaxon
: taxonSet
){
1351 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
1352 relatedTaxon
.removeSynonym(synonym
, config
.isNewHomotypicGroupIfNeeded());
1354 this.saveOrUpdate(synonym
);
1356 //TODO remove name from homotypical group?
1358 //remove synonym (if necessary)
1361 if (synonym
.getSynonymRelations().isEmpty()){
1362 TaxonNameBase
<?
,?
> name
= synonym
.getName();
1363 synonym
.setName(null);
1364 uuid
= dao
.delete(synonym
);
1366 //remove name if possible (and required)
1367 if (name
!= null && config
.isDeleteNameIfPossible()){
1369 nameService
.delete(name
, config
.getNameDeletionConfig());
1376 return uuid
.toString();
1378 return messages
.toString();
1386 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
1389 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
1391 return this.dao
.findIdenticalNamesNew(propertyPath
);
1395 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1398 public String
getPhylumName(TaxonNameBase name
){
1399 return this.dao
.getPhylumName(name
);
1403 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
1406 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
1407 return dao
.deleteSynonymRelationships(syn
, taxon
);
1411 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
1414 public long deleteSynonymRelationships(Synonym syn
) {
1415 return dao
.deleteSynonymRelationships(syn
, null);
1420 * @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)
1423 public List
<SynonymRelationship
> listSynonymRelationships(
1424 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
1425 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
1426 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
1428 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
1429 if(numberOfResults
> 0) { // no point checking again
1430 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
1436 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
1439 public Taxon
findBestMatchingTaxon(String taxonName
) {
1440 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
1441 config
.setTaxonNameTitle(taxonName
);
1442 return findBestMatchingTaxon(config
);
1448 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
1450 Taxon bestCandidate
= null;
1452 // 1. search for acceptet taxa
1453 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1454 boolean bestCandidateMatchesSecUuid
= false;
1455 boolean bestCandidateIsInClassification
= false;
1456 int countEqualCandidates
= 0;
1457 for(TaxonBase taxonBaseCandidate
: taxonList
){
1458 if(taxonBaseCandidate
instanceof Taxon
){
1459 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
1460 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
1461 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
1463 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
1464 bestCandidate
= newCanditate
;
1465 countEqualCandidates
= 1;
1466 bestCandidateMatchesSecUuid
= true;
1470 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
1471 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
1473 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
1474 bestCandidate
= newCanditate
;
1475 countEqualCandidates
= 1;
1476 bestCandidateIsInClassification
= true;
1479 if (bestCandidate
== null){
1480 bestCandidate
= newCanditate
;
1481 countEqualCandidates
= 1;
1485 }else{ //not Taxon.class
1488 countEqualCandidates
++;
1491 if (bestCandidate
!= null){
1492 if(countEqualCandidates
> 1){
1493 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
1494 return bestCandidate
;
1496 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
1497 return bestCandidate
;
1502 // 2. search for synonyms
1503 if (config
.isIncludeSynonyms()){
1504 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1505 for(TaxonBase taxonBase
: synonymList
){
1506 if(taxonBase
instanceof Synonym
){
1507 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
1508 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
1509 if(!acceptetdCandidates
.isEmpty()){
1510 bestCandidate
= acceptetdCandidates
.iterator().next();
1511 if(acceptetdCandidates
.size() == 1){
1512 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
1513 return bestCandidate
;
1515 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
1516 return bestCandidate
;
1518 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
1524 } catch (Exception e
){
1526 e
.printStackTrace();
1529 return bestCandidate
;
1532 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
1533 UUID configClassificationUuid
= config
.getClassificationUuid();
1534 if (configClassificationUuid
== null){
1537 for (TaxonNode node
: taxon
.getTaxonNodes()){
1538 UUID classUuid
= node
.getClassification().getUuid();
1539 if (configClassificationUuid
.equals(classUuid
)){
1546 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1547 UUID configSecUuid
= config
.getSecUuid();
1548 if (configSecUuid
== null){
1551 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1552 return configSecUuid
.equals(taxonSecUuid
);
1556 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1559 public Synonym
findBestMatchingSynonym(String taxonName
) {
1560 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1561 if(! synonymList
.isEmpty()){
1562 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1563 if(synonymList
.size() == 1){
1564 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1567 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1576 * @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)
1579 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1580 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1582 Synonym synonym
= oldSynonymRelation
.getSynonym();
1583 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1584 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1585 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1586 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1587 //set default relationship type
1588 if (newSynonymRelationshipType
== null){
1589 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1591 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1593 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1594 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1595 boolean isSingleInGroup
= !(hgSize
> 1);
1597 if (! isSingleInGroup
){
1598 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1599 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1600 if (isHomotypicToAccepted
){
1601 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.";
1602 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1603 message
= String
.format(message
, homotypicRelatives
);
1604 throw new HomotypicalGroupChangeException(message
);
1606 if (! moveHomotypicGroup
){
1607 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.";
1608 throw new HomotypicalGroupChangeException(message
);
1611 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1613 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1615 SynonymRelationship result
= null;
1616 //move all synonyms to new taxon
1617 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1618 for (Synonym syn
: homotypicSynonyms
){
1619 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1620 for (SynonymRelationship synRelation
: synRelations
){
1621 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1622 Reference
<?
> newReference
= reference
;
1623 if (newReference
== null && keepReference
){
1624 newReference
= synRelation
.getCitation();
1626 String newRefDetail
= referenceDetail
;
1627 if (newRefDetail
== null && keepReference
){
1628 newRefDetail
= synRelation
.getCitationMicroReference();
1630 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1631 fromTaxon
.removeSynonymRelation(synRelation
, false);
1633 //change homotypic group of synonym if relType is 'homotypic'
1634 // if (newRelTypeIsHomotypic){
1635 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1638 if (synRelation
.equals(oldSynonymRelation
)){
1639 result
= newSynRelation
;
1645 saveOrUpdate(newTaxon
);
1646 //Assert that there is a result
1647 if (result
== null){
1648 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1649 throw new IllegalStateException(message
);
1655 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1658 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1659 return dao
.getUuidAndTitleCacheTaxon();
1663 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1666 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1667 return dao
.getUuidAndTitleCacheSynonym();
1671 * @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)
1674 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1675 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1676 Classification classification
, List
<Language
> languages
,
1677 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1680 LuceneSearch luceneSearch
= prepareFindByFullTextSearch(clazz
, queryString
, classification
, languages
, highlightFragments
, null);
1682 // --- execute search
1683 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1685 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1686 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1688 // --- initialize taxa, thighlight matches ....
1689 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1690 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1691 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1693 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1694 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1698 public Pager
<SearchResult
<TaxonBase
>> findByDistribution(List
<NamedArea
> areaFilter
, List
<PresenceAbsenceTermBase
<?
>> statusFilter
,
1699 Classification classification
,
1700 Integer pageSize
, Integer pageNumber
,
1701 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws IOException
, ParseException
{
1703 LuceneSearch luceneSearch
= prepareByDistributionSearch(areaFilter
, statusFilter
, classification
);
1705 // --- execute search
1706 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1708 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1709 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1711 // --- initialize taxa, thighlight matches ....
1712 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1713 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1714 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1716 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1717 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1722 * @param queryString
1723 * @param classification
1725 * @param highlightFragments
1726 * @param sortFields TODO
1727 * @param directorySelectClass
1730 protected LuceneSearch
prepareFindByFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Language
> languages
,
1731 boolean highlightFragments
, SortField
[] sortFields
) {
1732 BooleanQuery finalQuery
= new BooleanQuery();
1733 BooleanQuery textQuery
= new BooleanQuery();
1735 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, TaxonBase
.class);
1736 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1738 if(sortFields
== null){
1739 sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1741 luceneSearch
.setSortFields(sortFields
);
1743 // ---- search criteria
1744 luceneSearch
.setCdmTypRestriction(clazz
);
1746 textQuery
.add(taxonBaseQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1747 textQuery
.add(taxonBaseQueryFactory
.newDefinedTermQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1749 finalQuery
.add(textQuery
, Occur
.MUST
);
1751 if(classification
!= null){
1752 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1754 luceneSearch
.setQuery(finalQuery
);
1756 if(highlightFragments
){
1757 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1759 return luceneSearch
;
1763 * Uses org.apache.lucene.search.join.JoinUtil for query time joining, alternatively
1764 * the BlockJoinQuery could be used. The latter might be more memory save but has the
1765 * drawback of requiring to do the join an indexing time.
1766 * see http://dev.e-taxonomy.eu/trac/wiki/LuceneNotes#JoinsinLucene for more information on this.
1768 * Joins TaxonRelationShip with Taxon depending on the direction of the given edge:
1770 * <li>direct, everted: {@link Direction.relatedTo}: TaxonRelationShip.relatedTo.id --> Taxon.id </li>
1771 * <li>inverse: {@link Direction.relatedFrom}: TaxonRelationShip.relatedFrom.id --> Taxon.id </li>
1773 * @param queryString
1774 * @param classification
1776 * @param highlightFragments
1777 * @param sortFields TODO
1780 * @throws IOException
1782 protected LuceneSearch
prepareFindByTaxonRelationFullTextSearch(TaxonRelationshipEdge edge
, String queryString
, Classification classification
, List
<Language
> languages
,
1783 boolean highlightFragments
, SortField
[] sortFields
) throws IOException
{
1786 String queryTermField
;
1787 String toField
= "id"; // TaxonBase.uuid
1789 if(edge
.isBidirectional()){
1790 throw new RuntimeException("Bidirectional joining not supported!");
1793 fromField
= "relatedFrom.id";
1794 queryTermField
= "relatedFrom.titleCache";
1795 } else if(edge
.isInvers()) {
1796 fromField
= "relatedTo.id";
1797 queryTermField
= "relatedTo.titleCache";
1799 throw new RuntimeException("Invalid direction: " + edge
.getDirections());
1802 BooleanQuery finalQuery
= new BooleanQuery();
1804 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, TaxonBase
.class);
1805 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1807 BooleanQuery joinFromQuery
= new BooleanQuery();
1808 joinFromQuery
.add(taxonBaseQueryFactory
.newTermQuery(queryTermField
, queryString
), Occur
.MUST
);
1809 joinFromQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("type.id", edge
.getTaxonRelationshipType()), Occur
.MUST
);
1810 Query joinQuery
= taxonBaseQueryFactory
.newJoinQuery(fromField
, toField
, joinFromQuery
, TaxonRelationship
.class);
1812 if(sortFields
== null){
1813 sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1815 luceneSearch
.setSortFields(sortFields
);
1817 finalQuery
.add(joinQuery
, Occur
.MUST
);
1819 if(classification
!= null){
1820 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1822 luceneSearch
.setQuery(finalQuery
);
1824 if(highlightFragments
){
1825 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1827 return luceneSearch
;
1834 * @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)
1837 public Pager
<SearchResult
<TaxonBase
>> findTaxaAndNamesByFullText(
1838 EnumSet
<TaxaAndNamesSearchMode
> searchModes
, String queryString
, Classification classification
,
1839 Set
<NamedArea
> namedAreas
, Set
<PresenceAbsenceTermBase
<?
>> distributionStatus
, List
<Language
> languages
,
1840 boolean highlightFragments
, Integer pageSize
,
1841 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
)
1842 throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
1844 // FIXME: allow taxonomic ordering
1845 // hql equivalent: order by t.name.genusOrUninomial, case when t.name.specificEpithet like '\"%\"' then 1 else 0 end, t.name.specificEpithet, t.name.rank desc, t.name.nameCache";
1846 // this require building a special sort column by a special classBridge
1847 if(highlightFragments
){
1848 logger
.warn("findTaxaAndNamesByFullText() : fragment highlighting is " +
1849 "currently not fully supported by this method and thus " +
1850 "may not work with common names and misapplied names.");
1853 // convert sets to lists
1854 List
<NamedArea
> namedAreaList
= null;
1855 List
<PresenceAbsenceTermBase
<?
>>distributionStatusList
= null;
1856 if(namedAreas
!= null){
1857 namedAreaList
= new ArrayList
<NamedArea
>(namedAreas
.size());
1858 namedAreaList
.addAll(namedAreas
);
1860 if(distributionStatus
!= null){
1861 distributionStatusList
= new ArrayList
<PresenceAbsenceTermBase
<?
>>(distributionStatus
.size());
1862 distributionStatusList
.addAll(distributionStatus
);
1865 // set default if parameter is null
1866 if(searchModes
== null){
1867 searchModes
= EnumSet
.of(TaxaAndNamesSearchMode
.doTaxa
);
1870 // set sort order and thus override any sort orders which may have been
1871 // defindes by prepare*Search methods
1872 if(orderHints
== null){
1873 orderHints
= OrderHint
.NOMENCLATURAL_SORT_ORDER
;
1875 SortField
[] sortFields
= new SortField
[orderHints
.size()];
1877 for(OrderHint oh
: orderHints
){
1878 sortFields
[i
++] = oh
.toSortField();
1880 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("id", SortField.STRING, false)};
1881 // SortField[] sortFields = new SortField[]{new SortField(NomenclaturalSortOrderBrigde.NAME_SORT_FIELD_NAME, SortField.STRING, false)};
1884 boolean addDistributionFilter
= namedAreas
!= null && namedAreas
.size() > 0;
1886 List
<LuceneSearch
> luceneSearches
= new ArrayList
<LuceneSearch
>();
1887 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1890 ======== filtering by distribution , HOWTO ========
1892 - http://www.javaranch.com/journal/2009/02/filtering-a-lucene-search.html
1893 - http://stackoverflow.com/questions/17709256/lucene-solr-using-complex-filters -> QueryWrapperFilter
1894 add Filter to search as http://lucene.apache.org/core/3_6_0/api/all/org/apache/lucene/search/Filter.html
1895 which will be put into a FilteredQuersy in the end ?
1898 3. how does it work in spatial?
1900 - http://www.nsshutdown.com/projects/lucene/whitepaper/locallucene_v2.html
1901 - http://www.infoq.com/articles/LuceneSpatialSupport
1902 - http://www.mhaller.de/archives/156-Spatial-search-with-Lucene.html
1903 ------------------------------------------------------------------------
1906 A) use a separate distribution filter per index sub-query/search:
1907 - byTaxonSyonym (query TaxaonBase):
1908 use a join area filter (Distribution -> TaxonBase)
1909 - byCommonName (query DescriptionElementBase): use an area filter on
1910 DescriptionElementBase !!! PROBLEM !!!
1911 This cannot work since the distributions are different entities than the
1912 common names and thus these are different lucene documents.
1913 - byMisaplliedNames (join query TaxonRelationship -> TaxaonBase):
1914 use a join area filter (Distribution -> TaxonBase)
1916 B) use a common distribution filter for all index sub-query/searches:
1917 - use a common join area filter (Distribution -> TaxonBase)
1918 - also implement the byCommonName as join query (CommonName -> TaxonBase)
1919 PROBLEM in this case: we are losing the fragment highlighting for the
1920 common names, since the returned documents are always TaxonBases
1923 /* The QueryFactory for creating filter queries on Distributions should
1924 * The query factory used for the common names query cannot be reused
1925 * for this case, since we want to only record the text fields which are
1926 * actually used in the primary query
1928 QueryFactory distributionFilterQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Distribution
.class);
1930 BooleanFilter multiIndexByAreaFilter
= new BooleanFilter();
1933 // search for taxa or synonyms
1934 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) || searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1935 Class taxonBaseSubclass
= TaxonBase
.class;
1936 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && !searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1937 taxonBaseSubclass
= Taxon
.class;
1938 } else if (!searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1939 taxonBaseSubclass
= Synonym
.class;
1941 luceneSearches
.add(prepareFindByFullTextSearch(taxonBaseSubclass
, queryString
, classification
, languages
, highlightFragments
, sortFields
));
1942 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1943 /* A) does not work!!!!
1944 if(addDistributionFilter){
1945 // in this case we need a filter which uses a join query
1946 // to get the TaxonBase documents for the DescriptionElementBase documents
1947 // which are matching the areas in question
1948 Query taxonAreaJoinQuery = createByDistributionJoinQuery(
1950 distributionStatusList,
1951 distributionFilterQueryFactory
1953 multiIndexByAreaFilter.add(new QueryWrapperFilter(taxonAreaJoinQuery), Occur.SHOULD);
1956 if(addDistributionFilter
&& searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1957 // add additional area filter for synonyms
1958 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
1959 String toField
= "accTaxon.id"; // id in TaxonBase index
1961 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, distributionFilterQueryFactory
);
1963 Query taxonAreaJoinQuery
= distributionFilterQueryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
1964 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
1969 // search by CommonTaxonName
1970 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxaByCommonNames
)) {
1972 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
1973 Query byCommonNameJoinQuery
= descriptionElementQueryFactory
.newJoinQuery(
1974 "inDescription.taxon.id",
1976 QueryFactory
.addTypeRestriction(
1977 createByDescriptionElementFullTextQuery(queryString
, classification
, null, languages
, descriptionElementQueryFactory
)
1978 , CommonTaxonName
.class
1980 CommonTaxonName
.class);
1981 logger
.debug("byCommonNameJoinQuery: " + byCommonNameJoinQuery
.toString());
1982 LuceneSearch byCommonNameSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
1983 byCommonNameSearch
.setCdmTypRestriction(Taxon
.class);
1984 byCommonNameSearch
.setQuery(byCommonNameJoinQuery
);
1985 byCommonNameSearch
.setSortFields(sortFields
);
1986 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1988 luceneSearches
.add(byCommonNameSearch
);
1990 /* A) does not work!!!!
1992 prepareByDescriptionElementFullTextSearch(CommonTaxonName.class,
1993 queryString, classification, null, languages, highlightFragments)
1995 idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id");
1996 if(addDistributionFilter){
1997 // in this case we are able to use DescriptionElementBase documents
1998 // which are matching the areas in question directly
1999 BooleanQuery byDistributionQuery = createByDistributionQuery(
2001 distributionStatusList,
2002 distributionFilterQueryFactory
2004 multiIndexByAreaFilter.add(new QueryWrapperFilter(byDistributionQuery), Occur.SHOULD);
2008 // search by misapplied names
2009 if(searchModes
.contains(TaxaAndNamesSearchMode
.doMisappliedNames
)) {
2011 // prepareFindByTaxonRelationFullTextSearch() is making use of JoinUtil.createJoinQuery()
2012 // which allows doing query time joins
2013 // finds the misapplied name (Taxon B) which is an misapplication for
2014 // a related Taxon A.
2016 luceneSearches
.add(prepareFindByTaxonRelationFullTextSearch(
2017 new TaxonRelationshipEdge(TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), Direction
.relatedTo
),
2018 queryString
, classification
, languages
, highlightFragments
, sortFields
));
2019 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
2021 if(addDistributionFilter
){
2022 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
2025 * Here i was facing wired and nasty bug which took me bugging be really for hours until I found this solution.
2026 * Maybe this is a but in java itself java.
2028 * When the string toField is constructed by using the expression TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString()
2031 * String toField = "relation." + TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString() +".to.id";
2033 * The byDistributionQuery fails, however when the uuid is first stored in another string variable the query
2034 * will execute as expected:
2036 * String misappliedNameForUuid = TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString();
2037 * String toField = "relation." + misappliedNameForUuid +".to.id";
2039 * Comparing both strings by the String.equals method returns true, so both String are identical.
2041 * The bug occurs when running eu.etaxonomy.cdm.api.service.TaxonServiceSearchTest in eclipse and in maven and seems to to be
2042 * dependent from a specific jvm (openjdk6 6b27-1.12.6-1ubuntu0.13.04.2, openjdk7 7u25-2.3.10-1ubuntu0.13.04.2, oracle jdk1.7.0_25 tested)
2043 * The bug is persistent after a reboot of the development computer.
2045 // String misappliedNameForUuid = TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString();
2046 // String toField = "relation." + misappliedNameForUuid +".to.id";
2047 String toField
= "relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id";
2048 // System.out.println("relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id".equals("relation." + misappliedNameForUuid +".to.id") ? " > identical" : " > different");
2049 // System.out.println("relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id".equals("relation." + TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString() +".to.id") ? " > identical" : " > different");
2051 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, distributionFilterQueryFactory
);
2052 Query taxonAreaJoinQuery
= distributionFilterQueryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
2053 QueryWrapperFilter filter
= new QueryWrapperFilter(taxonAreaJoinQuery
);
2055 // debug code for bug described above
2056 DocIdSet filterMatchSet
= filter
.getDocIdSet(luceneIndexToolProvider
.getIndexReaderFor(Taxon
.class));
2057 // System.err.println(DocIdBitSetPrinter.docsAsString(filterMatchSet, 100));
2059 multiIndexByAreaFilter
.add(filter
, Occur
.SHOULD
);
2063 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
,
2064 luceneSearches
.toArray(new LuceneSearch
[luceneSearches
.size()]));
2067 if(addDistributionFilter
){
2070 // in this case we need a filter which uses a join query
2071 // to get the TaxonBase documents for the DescriptionElementBase documents
2072 // which are matching the areas in question
2074 // for toTaxa, doByCommonName
2075 Query taxonAreaJoinQuery
= createByDistributionJoinQuery(
2077 distributionStatusList
,
2078 distributionFilterQueryFactory
2080 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
2083 if (addDistributionFilter
){
2084 multiSearch
.setFilter(multiIndexByAreaFilter
);
2088 // --- execute search
2089 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
2091 // --- initialize taxa, highlight matches ....
2092 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
2095 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
2096 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
2098 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
2099 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
2103 * @param namedAreaList at least one area must be in the list
2104 * @param distributionStatusList optional
2106 * @throws IOException
2108 protected Query
createByDistributionJoinQuery(
2109 List
<NamedArea
> namedAreaList
,
2110 List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
,
2111 QueryFactory queryFactory
2112 ) throws IOException
{
2114 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
2115 String toField
= "id"; // id in TaxonBase index
2117 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, queryFactory
);
2119 Query taxonAreaJoinQuery
= queryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
2121 return taxonAreaJoinQuery
;
2125 * @param namedAreaList
2126 * @param distributionStatusList
2127 * @param queryFactory
2130 private BooleanQuery
createByDistributionQuery(List
<NamedArea
> namedAreaList
,
2131 List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
, QueryFactory queryFactory
) {
2132 BooleanQuery areaQuery
= new BooleanQuery();
2133 // area field from Distribution
2134 areaQuery
.add(queryFactory
.newEntityIdsQuery("area.id", namedAreaList
), Occur
.MUST
);
2136 // status field from Distribution
2137 if(distributionStatusList
!= null && distributionStatusList
.size() > 0){
2138 areaQuery
.add(queryFactory
.newEntityIdsQuery("status.id", distributionStatusList
), Occur
.MUST
);
2141 logger
.debug("createByDistributionQuery() query: " + areaQuery
.toString());
2146 * This method has been primarily created for testing the area join query but might
2147 * also be useful in other situations
2149 * @param namedAreaList
2150 * @param distributionStatusList
2151 * @param classification
2152 * @param highlightFragments
2154 * @throws IOException
2156 protected LuceneSearch
prepareByDistributionSearch(
2157 List
<NamedArea
> namedAreaList
, List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
,
2158 Classification classification
) throws IOException
{
2160 BooleanQuery finalQuery
= new BooleanQuery();
2162 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
2164 // FIXME is this query factory using the wrong type?
2165 QueryFactory taxonQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Taxon
.class);
2167 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
2168 luceneSearch
.setSortFields(sortFields
);
2171 Query byAreaQuery
= createByDistributionJoinQuery(namedAreaList
, distributionStatusList
, taxonQueryFactory
);
2173 finalQuery
.add(byAreaQuery
, Occur
.MUST
);
2175 if(classification
!= null){
2176 finalQuery
.add(taxonQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
2179 logger
.info("prepareByAreaSearch() query: " + finalQuery
.toString());
2180 luceneSearch
.setQuery(finalQuery
);
2182 return luceneSearch
;
2188 * @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)
2191 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
2192 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
2193 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
2194 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
2197 LuceneSearch luceneSearch
= prepareByDescriptionElementFullTextSearch(clazz
, queryString
, classification
, features
, languages
, highlightFragments
);
2199 // --- execute search
2200 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
2202 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
2203 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
2205 // --- initialize taxa, highlight matches ....
2206 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
2207 @SuppressWarnings("rawtypes")
2208 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
2209 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
2211 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
2212 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
2218 public Pager
<SearchResult
<TaxonBase
>> findByEverythingFullText(String queryString
,
2219 Classification classification
, List
<Language
> languages
, boolean highlightFragments
,
2220 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
2222 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, null, languages
, highlightFragments
);
2223 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
, null);
2225 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
, luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
2227 // --- execute search
2228 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
2230 // --- initialize taxa, highlight matches ....
2231 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
2233 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
2234 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
2235 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
2237 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
2238 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
2240 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
2241 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
2248 * @param queryString
2249 * @param classification
2252 * @param highlightFragments
2253 * @param directorySelectClass
2256 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
,
2257 String queryString
, Classification classification
, List
<Feature
> features
,
2258 List
<Language
> languages
, boolean highlightFragments
) {
2260 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, DescriptionElementBase
.class);
2261 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
2263 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", SortField
.STRING
, false)};
2265 BooleanQuery finalQuery
= createByDescriptionElementFullTextQuery(queryString
, classification
, features
,
2266 languages
, descriptionElementQueryFactory
);
2268 luceneSearch
.setSortFields(sortFields
);
2269 luceneSearch
.setCdmTypRestriction(clazz
);
2270 luceneSearch
.setQuery(finalQuery
);
2271 if(highlightFragments
){
2272 luceneSearch
.setHighlightFields(descriptionElementQueryFactory
.getTextFieldNamesAsArray());
2275 return luceneSearch
;
2279 * @param queryString
2280 * @param classification
2283 * @param descriptionElementQueryFactory
2286 private BooleanQuery
createByDescriptionElementFullTextQuery(String queryString
, Classification classification
,
2287 List
<Feature
> features
, List
<Language
> languages
, QueryFactory descriptionElementQueryFactory
) {
2288 BooleanQuery finalQuery
= new BooleanQuery();
2289 BooleanQuery textQuery
= new BooleanQuery();
2290 textQuery
.add(descriptionElementQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
2294 if(languages
== null || languages
.size() == 0){
2295 nameQuery
= descriptionElementQueryFactory
.newTermQuery("name", queryString
);
2297 nameQuery
= new BooleanQuery();
2298 BooleanQuery languageSubQuery
= new BooleanQuery();
2299 for(Language lang
: languages
){
2300 languageSubQuery
.add(descriptionElementQueryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString(), false), Occur
.SHOULD
);
2302 ((BooleanQuery
) nameQuery
).add(descriptionElementQueryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
2303 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
2305 textQuery
.add(nameQuery
, Occur
.SHOULD
);
2308 // text field from TextData
2309 textQuery
.add(descriptionElementQueryFactory
.newMultilanguageTextQuery("text", queryString
, languages
), Occur
.SHOULD
);
2311 // --- TermBase fields - by representation ----
2312 // state field from CategoricalData
2313 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("stateData.state", queryString
, languages
), Occur
.SHOULD
);
2315 // state field from CategoricalData
2316 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("stateData.modifyingText", queryString
, languages
), Occur
.SHOULD
);
2318 // area field from Distribution
2319 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("area", queryString
, languages
), Occur
.SHOULD
);
2321 // status field from Distribution
2322 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("status", queryString
, languages
), Occur
.SHOULD
);
2324 finalQuery
.add(textQuery
, Occur
.MUST
);
2325 // --- classification ----
2327 if(classification
!= null){
2328 finalQuery
.add(descriptionElementQueryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
2331 // --- IdentifieableEntity fields - by uuid
2332 if(features
!= null && features
.size() > 0 ){
2333 finalQuery
.add(descriptionElementQueryFactory
.newEntityUuidsQuery("feature.uuid", features
), Occur
.MUST
);
2336 // the description must be associated with a taxon
2337 finalQuery
.add(descriptionElementQueryFactory
.newIsNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
2339 logger
.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery
.toString());
2344 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
2345 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
2346 * This method is a convenient means to retrieve a Lucene query string for such the fields.
2348 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
2349 * or {@link MultilanguageTextFieldBridge }
2350 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
2351 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
2352 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
2354 * TODO move to utiliy class !!!!!!!!
2356 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
2358 if(stringBuilder
== null){
2359 stringBuilder
= new StringBuilder();
2361 if(languages
== null || languages
.size() == 0){
2362 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
2364 for(Language lang
: languages
){
2365 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
2368 return stringBuilder
;
2372 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
2373 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2374 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
2376 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
2379 UUID nameUuid
= taxon
.getName().getUuid();
2380 ZoologicalName taxonName
= getZoologicalName(nameUuid
, zooHashMap
);
2381 String epithetOfTaxon
= null;
2382 String infragenericEpithetOfTaxon
= null;
2383 String infraspecificEpithetOfTaxon
= null;
2384 if (taxonName
.isSpecies()){
2385 epithetOfTaxon
= taxonName
.getSpecificEpithet();
2386 } else if (taxonName
.isInfraGeneric()){
2387 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
2388 } else if (taxonName
.isInfraSpecific()){
2389 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
2391 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
2392 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
2393 List
<String
> taxonNames
= new ArrayList
<String
>();
2395 for (TaxonNode node
: nodes
){
2396 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
2397 // List<String> synonymsEpithet = new ArrayList<String>();
2399 if (node
.getClassification().equals(classification
)){
2400 if (!node
.isTopmostNode()){
2401 TaxonNode parent
= node
.getParent();
2402 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
2403 TaxonNameBase
<?
,?
> parentName
= parent
.getTaxon().getName();
2404 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
2405 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
2406 Rank rankOfTaxon
= taxonName
.getRank();
2409 //create inferred synonyms for species, subspecies
2410 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
2412 Synonym inferredEpithet
= null;
2413 Synonym inferredGenus
= null;
2414 Synonym potentialCombination
= null;
2416 List
<String
> propertyPaths
= new ArrayList
<String
>();
2417 propertyPaths
.add("synonym");
2418 propertyPaths
.add("synonym.name");
2419 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
2420 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
2422 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2423 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2425 List
<TaxonRelationship
> taxonRelListParent
= null;
2426 List
<TaxonRelationship
> taxonRelListTaxon
= null;
2427 if (doWithMisappliedNames
){
2428 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2429 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2433 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
2436 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2437 Synonym syn
= synonymRelationOfParent
.getSynonym();
2439 inferredEpithet
= createInferredEpithets(taxon
,
2440 zooHashMap
, taxonName
, epithetOfTaxon
,
2441 infragenericEpithetOfTaxon
,
2442 infraspecificEpithetOfTaxon
,
2443 taxonNames
, parentName
,
2447 inferredSynonyms
.add(inferredEpithet
);
2448 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2449 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2452 if (doWithMisappliedNames
){
2454 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
2455 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2457 inferredEpithet
= createInferredEpithets(taxon
,
2458 zooHashMap
, taxonName
, epithetOfTaxon
,
2459 infragenericEpithetOfTaxon
,
2460 infraspecificEpithetOfTaxon
,
2461 taxonNames
, parentName
,
2464 inferredSynonyms
.add(inferredEpithet
);
2465 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2466 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2470 if (!taxonNames
.isEmpty()){
2471 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2472 ZoologicalName name
;
2473 if (!synNotInCDM
.isEmpty()){
2474 inferredSynonymsToBeRemoved
.clear();
2476 for (Synonym syn
:inferredSynonyms
){
2477 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2478 if (!synNotInCDM
.contains(name
.getNameCache())){
2479 inferredSynonymsToBeRemoved
.add(syn
);
2483 // Remove identified Synonyms from inferredSynonyms
2484 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2485 inferredSynonyms
.remove(synonym
);
2490 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
2493 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2494 TaxonNameBase synName
;
2495 ZoologicalName inferredSynName
;
2497 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2498 inferredGenus
= createInferredGenus(taxon
,
2499 zooHashMap
, taxonName
, epithetOfTaxon
,
2500 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
2502 inferredSynonyms
.add(inferredGenus
);
2503 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2504 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2509 if (doWithMisappliedNames
){
2511 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2512 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2513 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
2515 inferredSynonyms
.add(inferredGenus
);
2516 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2517 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2522 if (!taxonNames
.isEmpty()){
2523 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2524 ZoologicalName name
;
2525 if (!synNotInCDM
.isEmpty()){
2526 inferredSynonymsToBeRemoved
.clear();
2528 for (Synonym syn
:inferredSynonyms
){
2529 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2530 if (!synNotInCDM
.contains(name
.getNameCache())){
2531 inferredSynonymsToBeRemoved
.add(syn
);
2535 // Remove identified Synonyms from inferredSynonyms
2536 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2537 inferredSynonyms
.remove(synonym
);
2542 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
2544 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
2545 ZoologicalName inferredSynName
;
2546 //for all synonyms of the parent...
2547 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2548 TaxonNameBase synName
;
2549 Synonym synParent
= synonymRelationOfParent
.getSynonym();
2550 synName
= synParent
.getName();
2552 HibernateProxyHelper
.deproxy(synParent
);
2554 // Set the sourceReference
2555 sourceReference
= synParent
.getSec();
2557 // Determine the idInSource
2558 String idInSourceParent
= getIdInSource(synParent
);
2560 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2561 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2562 String synParentInfragenericName
= null;
2563 String synParentSpecificEpithet
= null;
2565 if (parentSynZooName
.isInfraGeneric()){
2566 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2568 if (parentSynZooName
.isSpecies()){
2569 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2572 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2573 synonymsGenus.put(synGenusName, idInSource);
2576 //for all synonyms of the taxon
2578 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2580 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2581 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2582 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
2584 synParentInfragenericName
,
2585 synParentSpecificEpithet
, syn
, zooHashMap
);
2587 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2588 inferredSynonyms
.add(potentialCombination
);
2589 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2590 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2597 if (doWithMisappliedNames
){
2599 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
2601 TaxonNameBase misappliedParentName
;
2603 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
2604 misappliedParentName
= misappliedParent
.getName();
2606 HibernateProxyHelper
.deproxy(misappliedParent
);
2608 // Set the sourceReference
2609 sourceReference
= misappliedParent
.getSec();
2611 // Determine the idInSource
2612 String idInSourceParent
= getIdInSource(misappliedParent
);
2614 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
2615 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2616 String synParentInfragenericName
= null;
2617 String synParentSpecificEpithet
= null;
2619 if (parentSynZooName
.isInfraGeneric()){
2620 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2622 if (parentSynZooName
.isSpecies()){
2623 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2627 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2628 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2629 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
2630 potentialCombination
= createPotentialCombination(
2631 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
2633 synParentInfragenericName
,
2634 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
2637 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2638 inferredSynonyms
.add(potentialCombination
);
2639 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2640 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2645 if (!taxonNames
.isEmpty()){
2646 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2647 ZoologicalName name
;
2648 if (!synNotInCDM
.isEmpty()){
2649 inferredSynonymsToBeRemoved
.clear();
2650 for (Synonym syn
:inferredSynonyms
){
2652 name
= (ZoologicalName
) syn
.getName();
2653 }catch (ClassCastException e
){
2654 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2656 if (!synNotInCDM
.contains(name
.getNameCache())){
2657 inferredSynonymsToBeRemoved
.add(syn
);
2660 // Remove identified Synonyms from inferredSynonyms
2661 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2662 inferredSynonyms
.remove(synonym
);
2668 logger
.info("The synonymrelationship type is not defined.");
2669 return inferredSynonyms
;
2676 return inferredSynonyms
;
2679 private Synonym
createPotentialCombination(String idInSourceParent
,
2680 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
2681 String synParentInfragenericName
, String synParentSpecificEpithet
,
2682 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2683 Synonym potentialCombination
;
2684 Reference sourceReference
;
2685 ZoologicalName inferredSynName
;
2686 HibernateProxyHelper
.deproxy(syn
);
2688 // Set sourceReference
2689 sourceReference
= syn
.getSec();
2690 if (sourceReference
== null){
2691 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2693 if (!parentSynZooName
.getTaxa().isEmpty()){
2694 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
2696 sourceReference
= taxon
.getSec();
2699 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
2701 String synTaxonInfraSpecificName
= null;
2703 if (parentSynZooName
.isSpecies()){
2704 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
2707 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
2708 synonymsEpithet.add(epithetName);
2711 //create potential combinations...
2712 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
2714 inferredSynName
.setGenusOrUninomial(synParentGenus
);
2715 if (zooSynName
.isSpecies()){
2716 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
2717 if (parentSynZooName
.isInfraGeneric()){
2718 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2721 if (zooSynName
.isInfraSpecific()){
2722 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
2723 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
2725 if (parentSynZooName
.isInfraGeneric()){
2726 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2730 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
2732 // Set the sourceReference
2733 potentialCombination
.setSec(sourceReference
);
2736 // Determine the idInSource
2737 String idInSourceSyn
= getIdInSource(syn
);
2739 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
2740 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
, idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2741 inferredSynName
.addSource(originalSource
);
2742 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
, idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2743 potentialCombination
.addSource(originalSource
);
2746 inferredSynName
.generateTitle();
2748 return potentialCombination
;
2751 private Synonym
createInferredGenus(Taxon taxon
,
2752 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2753 String epithetOfTaxon
, String genusOfTaxon
,
2754 List
<String
> taxonNames
, ZoologicalName zooParentName
,
2757 Synonym inferredGenus
;
2758 TaxonNameBase synName
;
2759 ZoologicalName inferredSynName
;
2760 synName
=syn
.getName();
2761 HibernateProxyHelper
.deproxy(syn
);
2763 // Determine the idInSource
2764 String idInSourceSyn
= getIdInSource(syn
);
2765 String idInSourceTaxon
= getIdInSource(taxon
);
2766 // Determine the sourceReference
2767 Reference sourceReference
= syn
.getSec();
2769 //logger.warn(sourceReference.getTitleCache());
2771 synName
= syn
.getName();
2772 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2773 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
2774 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
2775 synonymsEpithet.add(synSpeciesEpithetName);
2778 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2779 //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...
2782 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
2783 if (zooParentName
.isInfraGeneric()){
2784 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
2787 if (taxonName
.isSpecies()){
2788 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
2790 if (taxonName
.isInfraSpecific()){
2791 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2792 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
2796 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
2798 // Set the sourceReference
2799 inferredGenus
.setSec(sourceReference
);
2801 // Add the original source
2802 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
2803 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2804 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2805 inferredGenus
.addSource(originalSource
);
2807 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2808 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2809 inferredSynName
.addSource(originalSource
);
2810 originalSource
= null;
2813 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
2814 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2815 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2816 inferredGenus
.addSource(originalSource
);
2818 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2819 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2820 inferredSynName
.addSource(originalSource
);
2821 originalSource
= null;
2824 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
2826 inferredSynName
.generateTitle();
2829 return inferredGenus
;
2832 private Synonym
createInferredEpithets(Taxon taxon
,
2833 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2834 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
2835 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
2836 TaxonNameBase parentName
, TaxonBase syn
) {
2838 Synonym inferredEpithet
;
2839 TaxonNameBase
<?
,?
> synName
;
2840 ZoologicalName inferredSynName
;
2841 HibernateProxyHelper
.deproxy(syn
);
2843 // Determine the idInSource
2844 String idInSourceSyn
= getIdInSource(syn
);
2845 String idInSourceTaxon
= getIdInSource(taxon
);
2846 // Determine the sourceReference
2847 Reference
<?
> sourceReference
= syn
.getSec();
2849 if (sourceReference
== null){
2850 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
2851 sourceReference
= taxon
.getSec();
2854 synName
= syn
.getName();
2855 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2856 String synGenusName
= zooSynName
.getGenusOrUninomial();
2857 String synInfraGenericEpithet
= null;
2858 String synSpecificEpithet
= null;
2860 if (zooSynName
.getInfraGenericEpithet() != null){
2861 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
2864 if (zooSynName
.isInfraSpecific()){
2865 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
2868 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2869 synonymsGenus.put(synGenusName, idInSource);
2872 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2874 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
2875 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
2876 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
2878 inferredSynName
.setGenusOrUninomial(synGenusName
);
2880 if (parentName
.isInfraGeneric()){
2881 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
2883 if (taxonName
.isSpecies()){
2884 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2885 }else if (taxonName
.isInfraSpecific()){
2886 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
2887 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
2890 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
2892 // Set the sourceReference
2893 inferredEpithet
.setSec(sourceReference
);
2895 /* Add the original source
2896 if (idInSource != null) {
2897 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
2900 Reference citation = getCitation(syn);
2901 if (citation != null) {
2902 originalSource.setCitation(citation);
2903 inferredEpithet.addSource(originalSource);
2906 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
2909 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2910 taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2912 inferredEpithet
.addSource(originalSource
);
2914 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2915 taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2917 inferredSynName
.addSource(originalSource
);
2921 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
2923 inferredSynName
.generateTitle();
2924 return inferredEpithet
;
2928 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
2929 * Very likely only useful for createInferredSynonyms().
2934 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2935 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
2936 if (taxonName
== null) {
2937 taxonName
= zooHashMap
.get(uuid
);
2943 * Returns the idInSource for a given Synonym.
2946 private String
getIdInSource(TaxonBase taxonBase
) {
2947 String idInSource
= null;
2948 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
2949 if (sources
.size() == 1) {
2950 IdentifiableSource source
= sources
.iterator().next();
2951 if (source
!= null) {
2952 idInSource
= source
.getIdInSource();
2954 } else if (sources
.size() > 1) {
2957 for (IdentifiableSource source
: sources
) {
2958 idInSource
+= source
.getIdInSource();
2959 if (count
< sources
.size()) {
2964 } else if (sources
.size() == 0){
2965 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
2974 * Returns the citation for a given Synonym.
2977 private Reference
getCitation(Synonym syn
) {
2978 Reference citation
= null;
2979 Set
<IdentifiableSource
> sources
= syn
.getSources();
2980 if (sources
.size() == 1) {
2981 IdentifiableSource source
= sources
.iterator().next();
2982 if (source
!= null) {
2983 citation
= source
.getCitation();
2985 } else if (sources
.size() > 1) {
2986 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
2993 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
2994 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2996 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
2997 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
2998 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
3000 return inferredSynonyms
;
3004 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listClassifications(eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)
3007 public List
<Classification
> listClassifications(TaxonBase taxonBase
, Integer limit
, Integer start
, List
<String
> propertyPaths
) {
3009 // TODO quickly implemented, create according dao !!!!
3010 Set
<TaxonNode
> nodes
= new HashSet
<TaxonNode
>();
3011 Set
<Classification
> classifications
= new HashSet
<Classification
>();
3012 List
<Classification
> list
= new ArrayList
<Classification
>();
3014 if (taxonBase
== null) {
3018 taxonBase
= load(taxonBase
.getUuid());
3020 if (taxonBase
instanceof Taxon
) {
3021 nodes
.addAll(((Taxon
)taxonBase
).getTaxonNodes());
3023 for (Taxon taxon
: ((Synonym
)taxonBase
).getAcceptedTaxa() ) {
3024 nodes
.addAll(taxon
.getTaxonNodes());
3027 for (TaxonNode node
: nodes
) {
3028 classifications
.add(node
.getClassification());
3030 list
.addAll(classifications
);
3035 public Synonym
changeRelatedTaxonToSynonym(Taxon fromTaxon
, Taxon toTaxon
, TaxonRelationshipType oldRelationshipType
,
3036 SynonymRelationshipType synonymRelationshipType
) throws DataChangeNoRollbackException
{
3037 // Create new synonym using concept name
3038 TaxonNameBase
<?
, ?
> synonymName
= fromTaxon
.getName();
3039 Synonym synonym
= Synonym
.NewInstance(synonymName
, fromTaxon
.getSec());
3041 // Remove concept relation from taxon
3042 toTaxon
.removeTaxon(fromTaxon
, oldRelationshipType
);
3047 // Create a new synonym for the taxon
3048 SynonymRelationship synonymRelationship
;
3049 if (synonymRelationshipType
!= null
3050 && synonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF())){
3051 synonymRelationship
= toTaxon
.addHomotypicSynonym(synonym
, null, null);
3053 synonymRelationship
= toTaxon
.addHeterotypicSynonymName(synonymName
);
3056 this.saveOrUpdate(toTaxon
);
3057 //TODO: configurator and classification
3058 this.deleteTaxon(fromTaxon
, null, null);
3059 return synonymRelationship
.getSynonym();
3063 public List
<String
> isDeletable(TaxonBase taxonBase
, DeleteConfiguratorBase config
){
3064 List
<String
> result
= new ArrayList
<String
>();
3065 Set
<CdmBase
> references
= commonService
.getReferencingObjects(taxonBase
);
3066 if (taxonBase
instanceof Taxon
){
3067 TaxonDeletionConfigurator taxonConfig
= (TaxonDeletionConfigurator
) config
;
3068 result
= isDeletableForTaxon(references
, taxonConfig
);
3070 SynonymDeletionConfigurator synonymConfig
= (SynonymDeletionConfigurator
) config
;
3071 result
= isDeletableForSynonym(references
, synonymConfig
);
3076 private List
<String
> isDeletableForSynonym(Set
<CdmBase
> references
, SynonymDeletionConfigurator config
){
3078 List
<String
> result
= new ArrayList
<String
>();
3079 for (CdmBase ref
: references
){
3080 if (!(ref
instanceof SynonymRelationship
|| ref
instanceof Taxon
|| ref
instanceof TaxonNameBase
)){
3081 message
= "The Synonym can't be deleted as long as it is referenced by " + ref
.getClass().getSimpleName() + " with id "+ ref
.getId();
3082 result
.add(message
);
3088 private List
<String
> isDeletableForTaxon(Set
<CdmBase
> references
, TaxonDeletionConfigurator config
){
3090 List
<String
> result
= new ArrayList
<String
>();
3091 for (CdmBase ref
: references
){
3092 if (!(ref
instanceof TaxonNameBase
)){
3093 if (!config
.isDeleteSynonymRelations() && (ref
instanceof SynonymRelationship
)){
3094 message
= "The Taxon can't be deleted as long as it has synonyms.";
3095 result
.add(message
);
3097 if (!config
.isDeleteDescriptions() && (ref
instanceof DescriptionBase
)){
3098 message
= "The Taxon can't be deleted as long as it has factual data.";
3099 result
.add(message
);
3102 if (!config
.isDeleteTaxonNodes() && (ref
instanceof TaxonNode
)){
3103 message
= "The Taxon can't be deleted as long as it belongs to a taxon node.";
3104 result
.add(message
);
3106 if (!config
.isDeleteTaxonRelationships() && (ref
instanceof TaxonNode
)){
3107 if (!config
.isDeleteMisappliedNamesAndInvalidDesignations() && (((TaxonRelationship
)ref
).getType().equals(TaxonRelationshipType
.MISAPPLIED_NAME_FOR())|| ((TaxonRelationship
)ref
).getType().equals(TaxonRelationshipType
.INVALID_DESIGNATION_FOR()))){
3108 message
= "The Taxon can't be deleted as long as it has misapplied names or invalid designations.";
3109 result
.add(message
);
3111 message
= "The Taxon can't be deleted as long as it belongs to a taxon node.";
3112 result
.add(message
);
3115 if (ref
instanceof PolytomousKeyNode
){
3116 message
= "The Taxon can't be deleted as long as it is referenced by a polytomous key node.";
3117 result
.add(message
);
3120 if (HibernateProxyHelper
.isInstanceOf(ref
, IIdentificationKey
.class)){
3121 message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
3122 result
.add(message
);
3127 /* //PolytomousKeyNode
3128 if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){
3129 String message = "Taxon" + taxon.getTitleCache() + " can't be deleted as it is used in polytomous key node";
3134 if (ref
.isInstanceOf(TaxonInteraction
.class)){
3135 message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
3136 result
.add(message
);
3140 if (ref
.isInstanceOf(DeterminationEvent
.class)){
3141 message
= "Taxon can't be deleted as it is used in a determination event";
3142 result
.add(message
);