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
.IncludedTaxonConfiguration
;
43 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
44 import eu
.etaxonomy
.cdm
.api
.service
.config
.SynonymDeletionConfigurator
;
45 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
46 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonNodeDeletionConfigurator
.ChildHandling
;
47 import eu
.etaxonomy
.cdm
.api
.service
.dto
.IncludedTaxaDTO
;
48 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
49 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
50 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
51 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
52 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
53 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
54 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
55 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearch
;
56 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearchException
;
57 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
58 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
.TopGroupsWithMaxScore
;
59 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
60 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
61 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
62 import eu
.etaxonomy
.cdm
.api
.service
.util
.TaxonRelationshipEdge
;
63 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
64 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
65 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
66 import eu
.etaxonomy
.cdm
.hibernate
.search
.GroupByTaxonClassBridge
;
67 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
68 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
69 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
70 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
71 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
72 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
73 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
74 import eu
.etaxonomy
.cdm
.model
.common
.OriginalSourceType
;
75 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
76 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
77 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
78 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
79 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
80 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
81 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
82 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
83 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
84 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
85 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTerm
;
86 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
87 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
88 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
89 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
90 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
91 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
92 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
93 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
94 import eu
.etaxonomy
.cdm
.model
.molecular
.Amplification
;
95 import eu
.etaxonomy
.cdm
.model
.molecular
.AmplificationResult
;
96 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
97 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
98 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
99 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
100 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
101 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
102 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
103 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
104 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
105 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
106 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
107 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
108 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
109 import eu
.etaxonomy
.cdm
.model
.taxon
.ITaxonTreeNode
;
110 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
111 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
112 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
113 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
114 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
115 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
116 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
117 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
118 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
119 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
120 import eu
.etaxonomy
.cdm
.persistence
.dao
.initializer
.AbstractBeanInitializer
;
121 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
122 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
123 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.IClassificationDao
;
124 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
125 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
126 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
127 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
128 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
129 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
133 * @author a.kohlbecker
138 @Transactional(readOnly
= true)
139 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
140 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
142 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
144 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
146 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
150 private ITaxonNameDao nameDao
;
153 private INameService nameService
;
156 private ITaxonNodeService nodeService
;
159 private ICdmGenericDao genericDao
;
162 private IDescriptionService descriptionService
;
165 private IOrderedTermVocabularyDao orderedVocabularyDao
;
168 private IOccurrenceDao occurrenceDao
;
171 private IClassificationDao classificationDao
;
174 private AbstractBeanInitializer beanInitializer
;
177 private ILuceneIndexToolProvider luceneIndexToolProvider
;
182 public TaxonServiceImpl(){
183 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
187 * FIXME Candidate for harmonization
188 * rename searchByName ?
191 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
192 return dao
.getTaxaByName(name
, sec
);
196 * FIXME Candidate for harmonization
197 * merge with getRootTaxa(Reference sec, ..., ...)
199 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
202 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
203 if (cdmFetch
== null){
204 cdmFetch
= CdmFetch
.NO_FETCH();
206 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
210 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
211 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
215 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
216 return dao
.getAllRelationships(limit
, start
);
220 * FIXME Candidate for harmonization
221 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
225 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
227 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
228 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
229 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
230 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
231 return taxonRelTypeVocabulary
;
238 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
241 @Transactional(readOnly
= false)
242 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
244 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
245 synonymName
.removeTaxonBase(synonym
);
246 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
247 taxonName
.removeTaxonBase(acceptedTaxon
);
249 synonym
.setName(taxonName
);
250 acceptedTaxon
.setName(synonymName
);
252 // the accepted taxon needs a new uuid because the concept has changed
253 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
254 //acceptedTaxon.setUuid(UUID.randomUUID());
259 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
263 @Transactional(readOnly
= false)
264 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
266 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
267 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
268 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
270 //check synonym is not homotypic
271 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
272 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
273 throw new HomotypicalGroupChangeException(message
);
276 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
278 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
279 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
280 Set
<NameRelationship
> basionymsAndReplacedSynonyms
= synonymHomotypicGroup
.getBasionymAndReplacedSynonymRelations();
282 for (Synonym heteroSynonym
: heteroSynonyms
){
283 if (synonym
.equals(heteroSynonym
)){
284 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
287 //move synonyms in same homotypic group to new accepted taxon
288 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
292 //synonym.getName().removeTaxonBase(synonym);
295 // deleteSynonym(synonym, taxon, false);
298 SynonymDeletionConfigurator config
= new SynonymDeletionConfigurator();
299 config
.setDeleteNameIfPossible(false);
300 this.deleteSynonym(synonym
, acceptedTaxon
, config
);
302 } catch (Exception e
) {
303 logger
.info("Can't delete old synonym from database");
307 return newAcceptedTaxon
;
312 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
314 // Get name from synonym
315 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
317 /* // remove synonym from taxon
318 toTaxon.removeSynonym(synonym);
320 // Create a taxon with synonym name
321 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
323 // Add taxon relation
324 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
326 // since we are swapping names, we have to detach the name from the synonym completely.
327 // Otherwise the synonym will still be in the list of typified names.
328 // synonym.getName().removeTaxonBase(synonym);
329 this.deleteSynonym(synonym
, null);
336 * @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)
338 @Transactional(readOnly
= false)
340 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
341 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
343 TaxonNameBase synonymName
= synonym
.getName();
344 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
348 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
349 newHomotypicalGroup
.addTypifiedName(synonymName
);
351 //remove existing basionym relationships
352 synonymName
.removeBasionyms();
354 //add basionym relationship
355 if (setBasionymRelationIfApplicable
){
356 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
357 for (TaxonNameBase basionym
: basionyms
){
358 synonymName
.addBasionym(basionym
);
362 //set synonym relationship correctly
363 // SynonymRelationship relToTaxon = null;
364 boolean relToTargetTaxonExists
= false;
365 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
366 for (SynonymRelationship rel
: existingRelations
){
367 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
368 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
369 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
370 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
371 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
372 rel
.setType(newRelationType
);
373 //TODO handle citation and microCitation
376 relToTargetTaxonExists
= true;
378 if (removeFromOtherTaxa
){
379 acceptedTaxon
.removeSynonym(synonym
, false);
385 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
386 Taxon acceptedTaxon
= targetTaxon
;
387 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
388 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
389 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
390 //TODO handle citation and microCitation
391 Reference citation
= null;
392 String microCitation
= null;
393 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
400 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
403 @Transactional(readOnly
= false)
404 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
406 clazz
= TaxonBase
.class;
408 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
413 protected void setDao(ITaxonDao dao
) {
418 * @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)
421 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
422 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
424 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
425 if(numberOfResults
> 0) { // no point checking again
426 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
429 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
433 * @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)
436 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
437 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
439 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
440 if(numberOfResults
> 0) { // no point checking again
441 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
448 * @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)
451 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
452 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
454 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
455 if(numberOfResults
> 0) { // no point checking again
456 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
462 * @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)
465 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
466 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
468 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
469 if(numberOfResults
> 0) { // no point checking again
470 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
472 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
476 * @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)
479 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
480 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
482 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
483 if(numberOfResults
> 0) { // no point checking again
484 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
490 * @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)
493 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
494 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
496 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
497 if(numberOfResults
> 0) { // no point checking again
498 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
500 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
504 public List
<Taxon
> listAcceptedTaxaFor(UUID synonymUuid
, UUID classificationUuid
, Integer pageSize
, Integer pageNumber
,
505 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
506 return pageAcceptedTaxaFor(synonymUuid
, classificationUuid
, pageSize
, pageNumber
, orderHints
, propertyPaths
).getRecords();
510 public Pager
<Taxon
> pageAcceptedTaxaFor(UUID synonymUuid
, UUID classificationUuid
, Integer pageSize
, Integer pageNumber
,
511 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
513 List
<Taxon
> list
= new ArrayList
<Taxon
>();
516 Synonym synonym
= null;
519 synonym
= (Synonym
) dao
.load(synonymUuid
);
520 } catch (ClassCastException e
){
521 throw new EntityNotFoundException("The TaxonBase entity referenced by " + synonymUuid
+ " is not a Synonmy");
522 } catch (NullPointerException e
){
523 throw new EntityNotFoundException("No TaxonBase entity found for " + synonymUuid
);
526 Classification classificationFilter
= null;
527 if(classificationUuid
!= null){
529 classificationFilter
= classificationDao
.load(classificationUuid
);
530 } catch (NullPointerException e
){
531 throw new EntityNotFoundException("No Classification entity found for " + classificationUuid
);
533 if(classificationFilter
== null){
538 count
= dao
.countAcceptedTaxaFor(synonym
, classificationFilter
) ;
539 if(count
> (pageSize
* pageNumber
)){
540 list
= dao
.listAcceptedTaxaFor(synonym
, classificationFilter
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
543 return new DefaultPagerImpl
<Taxon
>(pageNumber
, count
.intValue(), pageSize
, list
);
549 * @param includeRelationships
553 * @param propertyPaths
554 * @return an List which is not specifically ordered
557 public Set
<Taxon
> listRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Integer maxDepth
,
558 Integer limit
, Integer start
, List
<String
> propertyPaths
) {
560 Set
<Taxon
> relatedTaxa
= collectRelatedTaxa(taxon
, includeRelationships
, new HashSet
<Taxon
>(), maxDepth
);
561 relatedTaxa
.remove(taxon
);
562 beanInitializer
.initializeAll(relatedTaxa
, propertyPaths
);
568 * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the
569 * <code>taxon</code> supplied as parameter.
572 * @param includeRelationships
574 * @param maxDepth can be <code>null</code> for infinite depth
577 private Set
<Taxon
> collectRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Set
<Taxon
> taxa
, Integer maxDepth
) {
583 if(includeRelationships
.isEmpty()){
587 if(maxDepth
!= null) {
590 if(logger
.isDebugEnabled()){
591 logger
.debug("collecting related taxa for " + taxon
+ " with maxDepth=" + maxDepth
);
593 List
<TaxonRelationship
> taxonRelationships
= dao
.getTaxonRelationships(taxon
, null, null, null, null, null, null);
594 for (TaxonRelationship taxRel
: taxonRelationships
) {
597 if (taxRel
.getToTaxon() == null || taxRel
.getFromTaxon() == null || taxRel
.getType() == null) {
600 // filter by includeRelationships
601 for (TaxonRelationshipEdge relationshipEdgeFilter
: includeRelationships
) {
602 if ( relationshipEdgeFilter
.getTaxonRelationshipType().equals(taxRel
.getType()) ) {
603 if (relationshipEdgeFilter
.getDirections().contains(Direction
.relatedTo
) && !taxa
.contains(taxRel
.getToTaxon())) {
604 if(logger
.isDebugEnabled()){
605 logger
.debug(maxDepth
+ ": " + taxon
.getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxRel
.getToTaxon().getTitleCache());
607 taxa
.add(taxRel
.getToTaxon());
608 if(maxDepth
== null || maxDepth
> 0) {
609 taxa
.addAll(collectRelatedTaxa(taxRel
.getToTaxon(), includeRelationships
, taxa
, maxDepth
));
612 if(relationshipEdgeFilter
.getDirections().contains(Direction
.relatedFrom
) && !taxa
.contains(taxRel
.getFromTaxon())) {
613 taxa
.add(taxRel
.getFromTaxon());
614 if(logger
.isDebugEnabled()){
615 logger
.debug(maxDepth
+ ": " +taxRel
.getFromTaxon().getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxon
.getTitleCache() );
617 if(maxDepth
== null || maxDepth
> 0) {
618 taxa
.addAll(collectRelatedTaxa(taxRel
.getFromTaxon(), includeRelationships
, taxa
, maxDepth
));
628 * @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)
631 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
632 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
634 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
635 if(numberOfResults
> 0) { // no point checking again
636 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
639 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
643 * @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)
646 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
647 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
649 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
650 if(numberOfResults
> 0) { // no point checking again
651 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
654 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
658 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
661 public List
<List
<Synonym
>> getSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
662 List
<List
<Synonym
>> result
= new ArrayList
<List
<Synonym
>>();
663 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
666 result
.add(t
.getHomotypicSynonymsByHomotypicGroup());
669 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
670 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
671 result
.add(t
.getSynonymsInGroup(homotypicalGroup
));
679 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
682 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
683 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
684 return t
.getHomotypicSynonymsByHomotypicGroup();
688 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
691 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
692 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
693 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
694 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
695 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
696 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
698 return heterotypicSynonymyGroups
;
702 public List
<UuidAndTitleCache
<IdentifiableEntity
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
704 List
<UuidAndTitleCache
<IdentifiableEntity
>> results
= new ArrayList
<UuidAndTitleCache
<IdentifiableEntity
>>();
707 if (configurator
.isDoSynonyms() || configurator
.isDoTaxa() || configurator
.isDoNamesWithoutTaxa()){
708 results
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.isDoNamesWithoutTaxa(), configurator
.isDoMisappliedNames(),configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
710 if (configurator
.isDoTaxaByCommonNames()) {
712 if(configurator
.getPageSize() == null ){
713 List
<UuidAndTitleCache
<IdentifiableEntity
>> commonNameResults
= dao
.getTaxaByCommonNameForEditor(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
714 if(commonNameResults
!= null){
715 results
.addAll(commonNameResults
);
723 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
726 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
728 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
729 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
730 List
<TaxonBase
> taxa
= null;
733 long numberTaxaResults
= 0L;
736 List
<String
> propertyPath
= new ArrayList
<String
>();
737 if(configurator
.getTaxonPropertyPath() != null){
738 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
742 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
743 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
745 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
746 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
747 configurator
.getNamedAreas());
750 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
751 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
752 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
753 configurator
.getMatchMode(), configurator
.getNamedAreas(),
754 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
758 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
761 results
.addAll(taxa
);
764 numberOfResults
+= numberTaxaResults
;
766 // Names without taxa
767 if (configurator
.isDoNamesWithoutTaxa()) {
768 int numberNameResults
= 0;
770 List
<?
extends TaxonNameBase
<?
,?
>> names
=
771 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
772 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
773 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
774 if (names
.size() > 0) {
775 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
776 if (taxonName
.getTaxonBases().size() == 0) {
777 results
.add(taxonName
);
781 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
782 numberOfResults
+= numberNameResults
;
786 // Taxa from common names
788 if (configurator
.isDoTaxaByCommonNames()) {
789 taxa
= new ArrayList
<TaxonBase
>();
790 numberTaxaResults
= 0;
791 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
792 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
794 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
795 List
<Taxon
> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
796 taxa
.addAll(commonNameResults
);
799 results
.addAll(taxa
);
801 numberOfResults
+= numberTaxaResults
;
805 return new DefaultPagerImpl
<IdentifiableEntity
>
806 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
809 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
810 return dao
.getUuidAndTitleCache();
814 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
817 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
818 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
819 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
820 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
821 for (TaxonDescription taxDesc
: descriptions
){
822 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
823 for (DescriptionElementBase descElem
: elements
){
824 for(Media media
: descElem
.getMedia()){
826 //find the best matching representation
827 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
836 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
839 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, boolean limitToGalleries
, List
<String
> propertyPath
){
840 return listMedia(taxon
, includeRelationships
, limitToGalleries
, true, false, false, propertyPath
);
845 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)
848 public List
<Media
> listMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
849 Boolean limitToGalleries
, Boolean includeTaxonDescriptions
, Boolean includeOccurrences
,
850 Boolean includeTaxonNameDescriptions
, List
<String
> propertyPath
) {
852 logger
.trace("listMedia() - START");
854 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
855 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
856 List
<Media
> nonImageGalleryImages
= new ArrayList
<Media
>();
858 if (limitToGalleries
== null) {
859 limitToGalleries
= false;
862 // --- resolve related taxa
863 if (includeRelationships
!= null && ! includeRelationships
.isEmpty()) {
864 logger
.trace("listMedia() - resolve related taxa");
865 taxa
= listRelatedTaxa(taxon
, includeRelationships
, null, null, null, null);
868 taxa
.add((Taxon
) dao
.load(taxon
.getUuid()));
870 if(includeTaxonDescriptions
!= null && includeTaxonDescriptions
){
871 logger
.trace("listMedia() - includeTaxonDescriptions");
872 List
<TaxonDescription
> taxonDescriptions
= new ArrayList
<TaxonDescription
>();
873 // --- TaxonDescriptions
874 for (Taxon t
: taxa
) {
875 taxonDescriptions
.addAll(descriptionService
.listTaxonDescriptions(t
, null, null, null, null, propertyPath
));
877 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
878 if (!limitToGalleries
|| taxonDescription
.isImageGallery()) {
879 for (DescriptionElementBase element
: taxonDescription
.getElements()) {
880 for (Media media
: element
.getMedia()) {
881 if(taxonDescription
.isImageGallery()){
882 taxonMedia
.add(media
);
885 nonImageGalleryImages
.add(media
);
891 //put images from image gallery first (#3242)
892 taxonMedia
.addAll(nonImageGalleryImages
);
896 if(includeOccurrences
!= null && includeOccurrences
) {
897 logger
.trace("listMedia() - includeOccurrences");
898 Set
<SpecimenOrObservationBase
> specimensOrObservations
= new HashSet
<SpecimenOrObservationBase
>();
900 for (Taxon t
: taxa
) {
901 specimensOrObservations
.addAll(occurrenceDao
.listByAssociatedTaxon(null, t
, null, null, null, null));
903 for (SpecimenOrObservationBase occurrence
: specimensOrObservations
) {
905 // direct media removed from specimen #3597
906 // taxonMedia.addAll(occurrence.getMedia());
908 // SpecimenDescriptions
909 Set
<SpecimenDescription
> specimenDescriptions
= occurrence
.getSpecimenDescriptions();
910 for (DescriptionBase specimenDescription
: specimenDescriptions
) {
911 if (!limitToGalleries
|| specimenDescription
.isImageGallery()) {
912 Set
<DescriptionElementBase
> elements
= specimenDescription
.getElements();
913 for (DescriptionElementBase element
: elements
) {
914 for (Media media
: element
.getMedia()) {
915 taxonMedia
.add(media
);
922 //TODO why may collections have media attached? #
923 if (occurrence
.isInstanceOf(DerivedUnit
.class)) {
924 DerivedUnit derivedUnit
= CdmBase
.deproxy(occurrence
, DerivedUnit
.class);
925 if (derivedUnit
.getCollection() != null){
926 taxonMedia
.addAll(derivedUnit
.getCollection().getMedia());
930 // pherograms & gelPhotos
931 if (occurrence
.isInstanceOf(DnaSample
.class)) {
932 DnaSample dnaSample
= CdmBase
.deproxy(occurrence
, DnaSample
.class);
933 Set
<Sequence
> sequences
= dnaSample
.getSequences();
934 //we do show only those gelPhotos which lead to a consensus sequence
935 for (Sequence sequence
: sequences
) {
936 Set
<Media
> dnaRelatedMedia
= new HashSet
<Media
>();
937 for (SingleRead singleRead
: sequence
.getSingleReads()){
938 AmplificationResult amplification
= singleRead
.getAmplificationResult();
939 dnaRelatedMedia
.add(amplification
.getGelPhoto());
940 dnaRelatedMedia
.add(singleRead
.getPherogram());
941 dnaRelatedMedia
.remove(null);
943 taxonMedia
.addAll(dnaRelatedMedia
);
950 if(includeTaxonNameDescriptions
!= null && includeTaxonNameDescriptions
) {
951 logger
.trace("listMedia() - includeTaxonNameDescriptions");
952 // --- TaxonNameDescription
953 Set
<TaxonNameDescription
> nameDescriptions
= new HashSet
<TaxonNameDescription
>();
954 for (Taxon t
: taxa
) {
955 nameDescriptions
.addAll(t
.getName().getDescriptions());
957 for(TaxonNameDescription nameDescription
: nameDescriptions
){
958 if (!limitToGalleries
|| nameDescription
.isImageGallery()) {
959 Set
<DescriptionElementBase
> elements
= nameDescription
.getElements();
960 for (DescriptionElementBase element
: elements
) {
961 for (Media media
: element
.getMedia()) {
962 taxonMedia
.add(media
);
970 logger
.trace("listMedia() - initialize");
971 beanInitializer
.initializeAll(taxonMedia
, propertyPath
);
973 logger
.trace("listMedia() - END");
979 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
982 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
983 return this.dao
.listByIds(listOfIDs
, null, null, null, null);
987 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
990 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
991 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
995 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
998 public int countAllRelationships() {
999 return this.dao
.countAllRelationships();
1006 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
1009 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
1010 return this.dao
.findIdenticalTaxonNames(propertyPath
);
1015 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
1018 public DeleteResult
deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
, Classification classification
) {
1020 if (config
== null){
1021 config
= new TaxonDeletionConfigurator();
1024 DeleteResult result
= isDeletable(taxon
, config
);
1027 // --- DeleteSynonymRelations
1028 if (config
.isDeleteSynonymRelations()){
1029 boolean removeSynonymNameFromHomotypicalGroup
= false;
1030 // use tmp Set to avoid concurrent modification
1031 Set
<SynonymRelationship
> synRelsToDelete
= new HashSet
<SynonymRelationship
>();
1032 synRelsToDelete
.addAll(taxon
.getSynonymRelations());
1033 for (SynonymRelationship synRel
: synRelsToDelete
){
1034 Synonym synonym
= synRel
.getSynonym();
1035 // taxon.removeSynonymRelation will set the accepted taxon and the synonym to NULL
1036 // this will cause hibernate to delete the relationship since
1037 // the SynonymRelationship field on both is annotated with removeOrphan
1038 // so no further explicit deleting of the relationship should be done here
1039 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
1041 // --- DeleteSynonymsIfPossible
1042 if (config
.isDeleteSynonymsIfPossible()){
1044 boolean newHomotypicGroupIfNeeded
= true;
1045 SynonymDeletionConfigurator synConfig
= new SynonymDeletionConfigurator();
1046 deleteSynonym(synonym
, taxon
, synConfig
);
1048 // relationship will be deleted by hibernate automatically,
1049 // see comment above and http://dev.e-taxonomy.eu/trac/ticket/3797
1051 // deleteSynonymRelationships(synonym, taxon);
1056 // --- DeleteTaxonRelationships
1057 if (! config
.isDeleteTaxonRelationships()){
1058 if (taxon
.getTaxonRelations().size() > 0){
1059 String message
= "Taxon can't be deleted as it is related to another taxon. " +
1060 "Remove taxon from all relations to other taxa prior to deletion.";
1061 // throw new ReferencedObjectUndeletableException(message);
1064 for (TaxonRelationship taxRel
: taxon
.getTaxonRelations()){
1065 if (config
.isDeleteMisappliedNamesAndInvalidDesignations()){
1066 if (taxRel
.getType().equals(TaxonRelationshipType
.MISAPPLIED_NAME_FOR()) || taxRel
.getType().equals(TaxonRelationshipType
.INVALID_DESIGNATION_FOR())){
1067 if (taxon
.equals(taxRel
.getToTaxon())){
1068 this.deleteTaxon(taxRel
.getFromTaxon(), config
, classification
);
1072 taxon
.removeTaxonRelation(taxRel
);
1073 /*if (taxFrom.equals(taxon)){
1075 this.deleteTaxon(taxTo, taxConf, classification);
1076 } catch(DataChangeNoRollbackException e){
1077 logger.debug("A related taxon will not be deleted." + e.getMessage());
1081 this.deleteTaxon(taxFrom, taxConf, classification);
1082 } catch(DataChangeNoRollbackException e){
1083 logger.debug("A related taxon will not be deleted." + e.getMessage());
1091 if (config
.isDeleteDescriptions()){
1092 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
1093 List
<TaxonDescription
> removeDescriptions
= new ArrayList
<TaxonDescription
>();
1094 for (TaxonDescription desc
: descriptions
){
1095 //TODO use description delete configurator ?
1096 //FIXME check if description is ALWAYS deletable
1097 if (desc
.getDescribedSpecimenOrObservation() != null){
1098 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
1099 " which also describes specimens or abservations";
1100 //throw new ReferencedObjectUndeletableException(message);
1102 removeDescriptions
.add(desc
);
1103 descriptionService
.delete(desc
);
1106 for (TaxonDescription desc
: removeDescriptions
){
1107 taxon
.removeDescription(desc
);
1112 /* //check references with only reverse mapping
1113 String message = checkForReferences(taxon);
1114 if (message != null){
1115 //throw new ReferencedObjectUndeletableException(message.toString());
1118 if (! config
.isDeleteTaxonNodes() || (!config
.isDeleteInAllClassifications() && classification
== null )){
1119 //if (taxon.getTaxonNodes().size() > 0){
1120 // 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.";
1121 // throw new ReferencedObjectUndeletableException(message);
1124 if (taxon
.getTaxonNodes().size() != 0){
1125 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1126 Iterator
<TaxonNode
> iterator
= nodes
.iterator();
1127 TaxonNode node
= null;
1128 boolean deleteChildren
;
1129 if (config
.getTaxonNodeConfig().getChildHandling().equals(ChildHandling
.DELETE
)){
1130 deleteChildren
= true;
1132 deleteChildren
= false;
1134 boolean success
= true;
1135 if (!config
.isDeleteInAllClassifications() && !(classification
== null)){
1136 while (iterator
.hasNext()){
1137 node
= iterator
.next();
1138 if (node
.getClassification().equals(classification
)){
1144 success
=taxon
.removeTaxonNode(node
, deleteChildren
);
1145 nodeService
.delete(node
);
1148 result
.addException(new Exception("The taxon can not be deleted because it is not used in defined classification."));
1150 } else if (config
.isDeleteInAllClassifications()){
1151 Set
<ITaxonTreeNode
> nodesList
= new HashSet
<ITaxonTreeNode
>();
1152 nodesList
.addAll(taxon
.getTaxonNodes());
1154 for (ITaxonTreeNode treeNode
: nodesList
){
1155 TaxonNode taxonNode
= (TaxonNode
) treeNode
;
1156 if(!deleteChildren
){
1157 /* Object[] childNodes = taxonNode.getChildNodes().toArray();
1158 //nodesList.addAll(taxonNode.getChildNodes());
1159 for (Object childNode: childNodes){
1160 TaxonNode childNodeCast = (TaxonNode) childNode;
1161 deleteTaxon(childNodeCast.getTaxon(), config, classification);
1165 /*for (TaxonNode childNode: taxonNode.getChildNodes()){
1166 deleteTaxon(childNode.getTaxon(), config, classification);
1169 // taxon.removeTaxonNode(taxonNode);
1170 //nodeService.delete(taxonNode);
1173 Object
[] childNodes
= taxonNode
.getChildNodes().toArray();
1174 for (Object childNode
: childNodes
){
1175 TaxonNode childNodeCast
= (TaxonNode
) childNode
;
1176 taxonNode
.getParent().addChildNode(childNodeCast
, childNodeCast
.getReference(), childNodeCast
.getMicroReference());
1179 //taxon.removeTaxonNode(taxonNode);
1182 config
.getTaxonNodeConfig().setDeleteTaxon(false);
1183 DeleteResult resultNodes
= nodeService
.deleteTaxonNodes(nodesList
, config
);
1184 if (!resultNodes
.isOk()){
1185 result
.addExceptions(resultNodes
.getExceptions());
1186 result
.setStatus(resultNodes
.getStatus());
1191 result
.addException(new Exception("The taxon can not be deleted because the taxon node can not be removed."));
1197 //PolytomousKey TODO
1201 if (config
.isDeleteNameIfPossible()){
1204 //TaxonNameBase name = nameService.find(taxon.getName().getUuid());
1205 TaxonNameBase name
= (TaxonNameBase
)HibernateProxyHelper
.deproxy(taxon
.getName());
1206 //check whether taxon will be deleted or not
1207 if ((taxon
.getTaxonNodes() == null || taxon
.getTaxonNodes().size()== 0) && name
!= null ){
1208 taxon
= (Taxon
) HibernateProxyHelper
.deproxy(taxon
);
1209 name
.removeTaxonBase(taxon
);
1210 nameService
.saveOrUpdate(name
);
1211 DeleteResult nameResult
= new DeleteResult();
1213 nameResult
= nameService
.delete(name
, config
.getNameDeletionConfig());
1215 if (nameResult
.isError()){
1216 //result.setError();
1217 result
.addRelatedObject(name
);
1218 result
.addExceptions(nameResult
.getExceptions());
1226 /* Set<TaxonDescription> descriptions = taxon.getDescriptions();
1228 for (TaxonDescription desc: descriptions){
1229 if (config.isDeleteDescriptions()){
1230 //TODO use description delete configurator ?
1231 //FIXME check if description is ALWAYS deletable
1232 taxon.removeDescription(desc);
1233 descriptionService.delete(desc);
1235 if (desc.getDescribedSpecimenOrObservations().size()>0){
1236 String message = "Taxon can't be deleted as it is used in a TaxonDescription" +
1237 " which also describes specimens or observations";
1238 throw new ReferencedObjectUndeletableException(message);
1243 if ((taxon
.getTaxonNodes() == null || taxon
.getTaxonNodes().size()== 0) ){
1245 UUID uuid
= dao
.delete(taxon
);
1247 }catch(Exception e
){
1248 result
.addException(e
);
1254 result
.addException(new Exception("The Taxon can't be deleted."));
1259 // List<Exception> exceptions = new ArrayList<Exception>();
1260 // for (String message: referencedObjects){
1261 // ReferencedObjectUndeletableException exception = new ReferencedObjectUndeletableException(message);
1262 // exceptions.add(exception);
1264 // result.addExceptions(exceptions);
1265 // result.setError();
1272 private String
checkForReferences(Taxon taxon
){
1273 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
1274 for (CdmBase referencingObject
: referencingObjects
){
1275 //IIdentificationKeys (Media, Polytomous, MultiAccess)
1276 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
1277 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";
1283 /* //PolytomousKeyNode
1284 if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){
1285 String message = "Taxon" + taxon.getTitleCache() + " can't be deleted as it is used in polytomous key node";
1290 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
1291 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
1296 if (referencingObject
.isInstanceOf(DeterminationEvent
.class)){
1297 String message
= "Taxon can't be deleted as it is used in a determination event";
1303 referencingObjects
= null;
1307 private boolean checkForPolytomousKeys(Taxon taxon
){
1308 boolean result
= false;
1309 List
<CdmBase
> list
= genericDao
.getCdmBasesByFieldAndClass(PolytomousKeyNode
.class, "taxon", taxon
);
1310 if (!list
.isEmpty()) {
1316 @Transactional(readOnly
= false)
1317 public UUID
delete(Synonym syn
){
1318 UUID result
= syn
.getUuid();
1319 this.deleteSynonym(syn
, null);
1326 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1328 @Transactional(readOnly
= false)
1330 public DeleteResult
deleteSynonym(Synonym synonym
, SynonymDeletionConfigurator config
) {
1331 return deleteSynonym(synonym
, null, config
);
1337 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1339 @Transactional(readOnly
= false)
1341 public DeleteResult
deleteSynonym(Synonym synonym
, Taxon taxon
, SynonymDeletionConfigurator config
) {
1342 DeleteResult result
= new DeleteResult();
1343 if (synonym
== null){
1348 if (config
== null){
1349 config
= new SynonymDeletionConfigurator();
1351 result
= isDeletable(synonym
, config
);
1355 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
1357 //remove synonymRelationship
1358 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
1360 taxonSet
.add(taxon
);
1362 taxonSet
.addAll(synonym
.getAcceptedTaxa());
1364 for (Taxon relatedTaxon
: taxonSet
){
1365 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
1366 relatedTaxon
.removeSynonym(synonym
, config
.isNewHomotypicGroupIfNeeded());
1368 this.saveOrUpdate(synonym
);
1370 //TODO remove name from homotypical group?
1372 //remove synonym (if necessary)
1375 if (synonym
.getSynonymRelations().isEmpty()){
1376 TaxonNameBase
<?
,?
> name
= synonym
.getName();
1377 synonym
.setName(null);
1378 uuid
= dao
.delete(synonym
);
1380 //remove name if possible (and required)
1381 if (name
!= null && config
.isDeleteNameIfPossible()){
1383 nameService
.delete(name
, config
.getNameDeletionConfig());
1389 result
.addException(new ReferencedObjectUndeletableException("Synonym can not be deleted it is used in a synonymRelationship."));
1397 // List<Exception> exceptions = new ArrayList<Exception>();
1398 // for (String message :messages){
1399 // exceptions.add(new ReferencedObjectUndeletableException(message));
1401 // result.setError();
1402 // result.addExceptions(exceptions);
1411 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
1414 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
1416 return this.dao
.findIdenticalNamesNew(propertyPath
);
1420 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1423 public String
getPhylumName(TaxonNameBase name
){
1424 return this.dao
.getPhylumName(name
);
1428 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
1431 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
1432 return dao
.deleteSynonymRelationships(syn
, taxon
);
1436 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
1439 public long deleteSynonymRelationships(Synonym syn
) {
1440 return dao
.deleteSynonymRelationships(syn
, null);
1445 * @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)
1448 public List
<SynonymRelationship
> listSynonymRelationships(
1449 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
1450 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
1451 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
1453 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
1454 if(numberOfResults
> 0) { // no point checking again
1455 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
1461 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
1464 public Taxon
findBestMatchingTaxon(String taxonName
) {
1465 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
1466 config
.setTaxonNameTitle(taxonName
);
1467 return findBestMatchingTaxon(config
);
1473 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
1475 Taxon bestCandidate
= null;
1477 // 1. search for acceptet taxa
1478 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1479 boolean bestCandidateMatchesSecUuid
= false;
1480 boolean bestCandidateIsInClassification
= false;
1481 int countEqualCandidates
= 0;
1482 for(TaxonBase taxonBaseCandidate
: taxonList
){
1483 if(taxonBaseCandidate
instanceof Taxon
){
1484 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
1485 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
1486 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
1488 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
1489 bestCandidate
= newCanditate
;
1490 countEqualCandidates
= 1;
1491 bestCandidateMatchesSecUuid
= true;
1495 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
1496 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
1498 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
1499 bestCandidate
= newCanditate
;
1500 countEqualCandidates
= 1;
1501 bestCandidateIsInClassification
= true;
1504 if (bestCandidate
== null){
1505 bestCandidate
= newCanditate
;
1506 countEqualCandidates
= 1;
1510 }else{ //not Taxon.class
1513 countEqualCandidates
++;
1516 if (bestCandidate
!= null){
1517 if(countEqualCandidates
> 1){
1518 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
1519 return bestCandidate
;
1521 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
1522 return bestCandidate
;
1527 // 2. search for synonyms
1528 if (config
.isIncludeSynonyms()){
1529 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1530 for(TaxonBase taxonBase
: synonymList
){
1531 if(taxonBase
instanceof Synonym
){
1532 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
1533 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
1534 if(!acceptetdCandidates
.isEmpty()){
1535 bestCandidate
= acceptetdCandidates
.iterator().next();
1536 if(acceptetdCandidates
.size() == 1){
1537 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
1538 return bestCandidate
;
1540 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
1541 return bestCandidate
;
1543 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
1549 } catch (Exception e
){
1551 e
.printStackTrace();
1554 return bestCandidate
;
1557 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
1558 UUID configClassificationUuid
= config
.getClassificationUuid();
1559 if (configClassificationUuid
== null){
1562 for (TaxonNode node
: taxon
.getTaxonNodes()){
1563 UUID classUuid
= node
.getClassification().getUuid();
1564 if (configClassificationUuid
.equals(classUuid
)){
1571 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1572 UUID configSecUuid
= config
.getSecUuid();
1573 if (configSecUuid
== null){
1576 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1577 return configSecUuid
.equals(taxonSecUuid
);
1581 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1584 public Synonym
findBestMatchingSynonym(String taxonName
) {
1585 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1586 if(! synonymList
.isEmpty()){
1587 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1588 if(synonymList
.size() == 1){
1589 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1592 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1601 * @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)
1604 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1605 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1607 Synonym synonym
= oldSynonymRelation
.getSynonym();
1608 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1609 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1610 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1611 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1612 //set default relationship type
1613 if (newSynonymRelationshipType
== null){
1614 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1616 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1618 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1619 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1620 boolean isSingleInGroup
= !(hgSize
> 1);
1622 if (! isSingleInGroup
){
1623 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1624 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1625 if (isHomotypicToAccepted
){
1626 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.";
1627 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1628 message
= String
.format(message
, homotypicRelatives
);
1629 throw new HomotypicalGroupChangeException(message
);
1631 if (! moveHomotypicGroup
){
1632 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.";
1633 throw new HomotypicalGroupChangeException(message
);
1636 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1638 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1640 SynonymRelationship result
= null;
1641 //move all synonyms to new taxon
1642 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1643 for (Synonym syn
: homotypicSynonyms
){
1644 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1645 for (SynonymRelationship synRelation
: synRelations
){
1646 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1647 Reference
<?
> newReference
= reference
;
1648 if (newReference
== null && keepReference
){
1649 newReference
= synRelation
.getCitation();
1651 String newRefDetail
= referenceDetail
;
1652 if (newRefDetail
== null && keepReference
){
1653 newRefDetail
= synRelation
.getCitationMicroReference();
1655 newTaxon
= HibernateProxyHelper
.deproxy(newTaxon
, Taxon
.class);
1656 fromTaxon
= HibernateProxyHelper
.deproxy(fromTaxon
, Taxon
.class);
1657 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1658 fromTaxon
.removeSynonymRelation(synRelation
, false);
1660 //change homotypic group of synonym if relType is 'homotypic'
1661 // if (newRelTypeIsHomotypic){
1662 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1665 if (synRelation
.equals(oldSynonymRelation
)){
1666 result
= newSynRelation
;
1672 saveOrUpdate(fromTaxon
);
1673 saveOrUpdate(newTaxon
);
1674 //Assert that there is a result
1675 if (result
== null){
1676 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1677 throw new IllegalStateException(message
);
1683 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1686 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1687 return dao
.getUuidAndTitleCacheTaxon();
1691 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1694 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1695 return dao
.getUuidAndTitleCacheSynonym();
1699 * @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)
1702 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1703 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1704 Classification classification
, List
<Language
> languages
,
1705 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1708 LuceneSearch luceneSearch
= prepareFindByFullTextSearch(clazz
, queryString
, classification
, languages
, highlightFragments
, null);
1710 // --- execute search
1711 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1713 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1714 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1716 // --- initialize taxa, thighlight matches ....
1717 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1718 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1719 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1721 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1722 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1726 public Pager
<SearchResult
<TaxonBase
>> findByDistribution(List
<NamedArea
> areaFilter
, List
<PresenceAbsenceTerm
> statusFilter
,
1727 Classification classification
,
1728 Integer pageSize
, Integer pageNumber
,
1729 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws IOException
, ParseException
{
1731 LuceneSearch luceneSearch
= prepareByDistributionSearch(areaFilter
, statusFilter
, classification
);
1733 // --- execute search
1734 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1736 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1737 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1739 // --- initialize taxa, thighlight matches ....
1740 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1741 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1742 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1744 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1745 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1750 * @param queryString
1751 * @param classification
1753 * @param highlightFragments
1754 * @param sortFields TODO
1755 * @param directorySelectClass
1758 protected LuceneSearch
prepareFindByFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Language
> languages
,
1759 boolean highlightFragments
, SortField
[] sortFields
) {
1760 BooleanQuery finalQuery
= new BooleanQuery();
1761 BooleanQuery textQuery
= new BooleanQuery();
1763 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, TaxonBase
.class);
1764 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1766 if(sortFields
== null){
1767 sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1769 luceneSearch
.setSortFields(sortFields
);
1771 // ---- search criteria
1772 luceneSearch
.setCdmTypRestriction(clazz
);
1774 textQuery
.add(taxonBaseQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1775 textQuery
.add(taxonBaseQueryFactory
.newDefinedTermQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1777 finalQuery
.add(textQuery
, Occur
.MUST
);
1779 if(classification
!= null){
1780 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1782 luceneSearch
.setQuery(finalQuery
);
1784 if(highlightFragments
){
1785 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1787 return luceneSearch
;
1791 * Uses org.apache.lucene.search.join.JoinUtil for query time joining, alternatively
1792 * the BlockJoinQuery could be used. The latter might be more memory save but has the
1793 * drawback of requiring to do the join an indexing time.
1794 * see http://dev.e-taxonomy.eu/trac/wiki/LuceneNotes#JoinsinLucene for more information on this.
1796 * Joins TaxonRelationShip with Taxon depending on the direction of the given edge:
1798 * <li>direct, everted: {@link Direction.relatedTo}: TaxonRelationShip.relatedTo.id --> Taxon.id </li>
1799 * <li>inverse: {@link Direction.relatedFrom}: TaxonRelationShip.relatedFrom.id --> Taxon.id </li>
1801 * @param queryString
1802 * @param classification
1804 * @param highlightFragments
1805 * @param sortFields TODO
1808 * @throws IOException
1810 protected LuceneSearch
prepareFindByTaxonRelationFullTextSearch(TaxonRelationshipEdge edge
, String queryString
, Classification classification
, List
<Language
> languages
,
1811 boolean highlightFragments
, SortField
[] sortFields
) throws IOException
{
1814 String queryTermField
;
1815 String toField
= "id"; // TaxonBase.uuid
1817 if(edge
.isBidirectional()){
1818 throw new RuntimeException("Bidirectional joining not supported!");
1821 fromField
= "relatedFrom.id";
1822 queryTermField
= "relatedFrom.titleCache";
1823 } else if(edge
.isInvers()) {
1824 fromField
= "relatedTo.id";
1825 queryTermField
= "relatedTo.titleCache";
1827 throw new RuntimeException("Invalid direction: " + edge
.getDirections());
1830 BooleanQuery finalQuery
= new BooleanQuery();
1832 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, TaxonBase
.class);
1833 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1835 BooleanQuery joinFromQuery
= new BooleanQuery();
1836 joinFromQuery
.add(taxonBaseQueryFactory
.newTermQuery(queryTermField
, queryString
), Occur
.MUST
);
1837 joinFromQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("type.id", edge
.getTaxonRelationshipType()), Occur
.MUST
);
1838 Query joinQuery
= taxonBaseQueryFactory
.newJoinQuery(fromField
, toField
, joinFromQuery
, TaxonRelationship
.class);
1840 if(sortFields
== null){
1841 sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1843 luceneSearch
.setSortFields(sortFields
);
1845 finalQuery
.add(joinQuery
, Occur
.MUST
);
1847 if(classification
!= null){
1848 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1850 luceneSearch
.setQuery(finalQuery
);
1852 if(highlightFragments
){
1853 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1855 return luceneSearch
;
1862 * @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)
1865 public Pager
<SearchResult
<TaxonBase
>> findTaxaAndNamesByFullText(
1866 EnumSet
<TaxaAndNamesSearchMode
> searchModes
, String queryString
, Classification classification
,
1867 Set
<NamedArea
> namedAreas
, Set
<PresenceAbsenceTerm
> distributionStatus
, List
<Language
> languages
,
1868 boolean highlightFragments
, Integer pageSize
,
1869 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
)
1870 throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
1872 // FIXME: allow taxonomic ordering
1873 // 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";
1874 // this require building a special sort column by a special classBridge
1875 if(highlightFragments
){
1876 logger
.warn("findTaxaAndNamesByFullText() : fragment highlighting is " +
1877 "currently not fully supported by this method and thus " +
1878 "may not work with common names and misapplied names.");
1881 // convert sets to lists
1882 List
<NamedArea
> namedAreaList
= null;
1883 List
<PresenceAbsenceTerm
>distributionStatusList
= null;
1884 if(namedAreas
!= null){
1885 namedAreaList
= new ArrayList
<NamedArea
>(namedAreas
.size());
1886 namedAreaList
.addAll(namedAreas
);
1888 if(distributionStatus
!= null){
1889 distributionStatusList
= new ArrayList
<PresenceAbsenceTerm
>(distributionStatus
.size());
1890 distributionStatusList
.addAll(distributionStatus
);
1893 // set default if parameter is null
1894 if(searchModes
== null){
1895 searchModes
= EnumSet
.of(TaxaAndNamesSearchMode
.doTaxa
);
1898 // set sort order and thus override any sort orders which may have been
1899 // defindes by prepare*Search methods
1900 if(orderHints
== null){
1901 orderHints
= OrderHint
.NOMENCLATURAL_SORT_ORDER
;
1903 SortField
[] sortFields
= new SortField
[orderHints
.size()];
1905 for(OrderHint oh
: orderHints
){
1906 sortFields
[i
++] = oh
.toSortField();
1908 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("id", SortField.STRING, false)};
1909 // SortField[] sortFields = new SortField[]{new SortField(NomenclaturalSortOrderBrigde.NAME_SORT_FIELD_NAME, SortField.STRING, false)};
1912 boolean addDistributionFilter
= namedAreas
!= null && namedAreas
.size() > 0;
1914 List
<LuceneSearch
> luceneSearches
= new ArrayList
<LuceneSearch
>();
1915 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1918 ======== filtering by distribution , HOWTO ========
1920 - http://www.javaranch.com/journal/2009/02/filtering-a-lucene-search.html
1921 - http://stackoverflow.com/questions/17709256/lucene-solr-using-complex-filters -> QueryWrapperFilter
1922 add Filter to search as http://lucene.apache.org/core/3_6_0/api/all/org/apache/lucene/search/Filter.html
1923 which will be put into a FilteredQuersy in the end ?
1926 3. how does it work in spatial?
1928 - http://www.nsshutdown.com/projects/lucene/whitepaper/locallucene_v2.html
1929 - http://www.infoq.com/articles/LuceneSpatialSupport
1930 - http://www.mhaller.de/archives/156-Spatial-search-with-Lucene.html
1931 ------------------------------------------------------------------------
1934 A) use a separate distribution filter per index sub-query/search:
1935 - byTaxonSyonym (query TaxaonBase):
1936 use a join area filter (Distribution -> TaxonBase)
1937 - byCommonName (query DescriptionElementBase): use an area filter on
1938 DescriptionElementBase !!! PROBLEM !!!
1939 This cannot work since the distributions are different entities than the
1940 common names and thus these are different lucene documents.
1941 - byMisaplliedNames (join query TaxonRelationship -> TaxaonBase):
1942 use a join area filter (Distribution -> TaxonBase)
1944 B) use a common distribution filter for all index sub-query/searches:
1945 - use a common join area filter (Distribution -> TaxonBase)
1946 - also implement the byCommonName as join query (CommonName -> TaxonBase)
1947 PROBLEM in this case: we are losing the fragment highlighting for the
1948 common names, since the returned documents are always TaxonBases
1951 /* The QueryFactory for creating filter queries on Distributions should
1952 * The query factory used for the common names query cannot be reused
1953 * for this case, since we want to only record the text fields which are
1954 * actually used in the primary query
1956 QueryFactory distributionFilterQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Distribution
.class);
1958 BooleanFilter multiIndexByAreaFilter
= new BooleanFilter();
1961 // search for taxa or synonyms
1962 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) || searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1963 Class taxonBaseSubclass
= TaxonBase
.class;
1964 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && !searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1965 taxonBaseSubclass
= Taxon
.class;
1966 } else if (!searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1967 taxonBaseSubclass
= Synonym
.class;
1969 luceneSearches
.add(prepareFindByFullTextSearch(taxonBaseSubclass
, queryString
, classification
, languages
, highlightFragments
, sortFields
));
1970 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1971 /* A) does not work!!!!
1972 if(addDistributionFilter){
1973 // in this case we need a filter which uses a join query
1974 // to get the TaxonBase documents for the DescriptionElementBase documents
1975 // which are matching the areas in question
1976 Query taxonAreaJoinQuery = createByDistributionJoinQuery(
1978 distributionStatusList,
1979 distributionFilterQueryFactory
1981 multiIndexByAreaFilter.add(new QueryWrapperFilter(taxonAreaJoinQuery), Occur.SHOULD);
1984 if(addDistributionFilter
&& searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1985 // add additional area filter for synonyms
1986 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
1987 String toField
= "accTaxon.id"; // id in TaxonBase index
1989 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, distributionFilterQueryFactory
);
1991 Query taxonAreaJoinQuery
= distributionFilterQueryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
1992 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
1997 // search by CommonTaxonName
1998 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxaByCommonNames
)) {
2000 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
2001 Query byCommonNameJoinQuery
= descriptionElementQueryFactory
.newJoinQuery(
2002 "inDescription.taxon.id",
2004 QueryFactory
.addTypeRestriction(
2005 createByDescriptionElementFullTextQuery(queryString
, classification
, null, languages
, descriptionElementQueryFactory
)
2006 , CommonTaxonName
.class
2008 CommonTaxonName
.class);
2009 logger
.debug("byCommonNameJoinQuery: " + byCommonNameJoinQuery
.toString());
2010 LuceneSearch byCommonNameSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
2011 byCommonNameSearch
.setCdmTypRestriction(Taxon
.class);
2012 byCommonNameSearch
.setQuery(byCommonNameJoinQuery
);
2013 byCommonNameSearch
.setSortFields(sortFields
);
2014 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
2016 luceneSearches
.add(byCommonNameSearch
);
2018 /* A) does not work!!!!
2020 prepareByDescriptionElementFullTextSearch(CommonTaxonName.class,
2021 queryString, classification, null, languages, highlightFragments)
2023 idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id");
2024 if(addDistributionFilter){
2025 // in this case we are able to use DescriptionElementBase documents
2026 // which are matching the areas in question directly
2027 BooleanQuery byDistributionQuery = createByDistributionQuery(
2029 distributionStatusList,
2030 distributionFilterQueryFactory
2032 multiIndexByAreaFilter.add(new QueryWrapperFilter(byDistributionQuery), Occur.SHOULD);
2036 // search by misapplied names
2037 if(searchModes
.contains(TaxaAndNamesSearchMode
.doMisappliedNames
)) {
2039 // prepareFindByTaxonRelationFullTextSearch() is making use of JoinUtil.createJoinQuery()
2040 // which allows doing query time joins
2041 // finds the misapplied name (Taxon B) which is an misapplication for
2042 // a related Taxon A.
2044 luceneSearches
.add(prepareFindByTaxonRelationFullTextSearch(
2045 new TaxonRelationshipEdge(TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), Direction
.relatedTo
),
2046 queryString
, classification
, languages
, highlightFragments
, sortFields
));
2047 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
2049 if(addDistributionFilter
){
2050 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
2053 * Here i was facing wired and nasty bug which took me bugging be really for hours until I found this solution.
2054 * Maybe this is a but in java itself java.
2056 * When the string toField is constructed by using the expression TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString()
2059 * String toField = "relation." + TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString() +".to.id";
2061 * The byDistributionQuery fails, however when the uuid is first stored in another string variable the query
2062 * will execute as expected:
2064 * String misappliedNameForUuid = TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString();
2065 * String toField = "relation." + misappliedNameForUuid +".to.id";
2067 * Comparing both strings by the String.equals method returns true, so both String are identical.
2069 * The bug occurs when running eu.etaxonomy.cdm.api.service.TaxonServiceSearchTest in eclipse and in maven and seems to to be
2070 * 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)
2071 * The bug is persistent after a reboot of the development computer.
2073 // String misappliedNameForUuid = TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString();
2074 // String toField = "relation." + misappliedNameForUuid +".to.id";
2075 String toField
= "relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id";
2076 // System.out.println("relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id".equals("relation." + misappliedNameForUuid +".to.id") ? " > identical" : " > different");
2077 // System.out.println("relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id".equals("relation." + TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString() +".to.id") ? " > identical" : " > different");
2079 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, distributionFilterQueryFactory
);
2080 Query taxonAreaJoinQuery
= distributionFilterQueryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
2081 QueryWrapperFilter filter
= new QueryWrapperFilter(taxonAreaJoinQuery
);
2083 // debug code for bug described above
2084 DocIdSet filterMatchSet
= filter
.getDocIdSet(luceneIndexToolProvider
.getIndexReaderFor(Taxon
.class));
2085 // System.err.println(DocIdBitSetPrinter.docsAsString(filterMatchSet, 100));
2087 multiIndexByAreaFilter
.add(filter
, Occur
.SHOULD
);
2091 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
,
2092 luceneSearches
.toArray(new LuceneSearch
[luceneSearches
.size()]));
2095 if(addDistributionFilter
){
2098 // in this case we need a filter which uses a join query
2099 // to get the TaxonBase documents for the DescriptionElementBase documents
2100 // which are matching the areas in question
2102 // for toTaxa, doByCommonName
2103 Query taxonAreaJoinQuery
= createByDistributionJoinQuery(
2105 distributionStatusList
,
2106 distributionFilterQueryFactory
2108 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
2111 if (addDistributionFilter
){
2112 multiSearch
.setFilter(multiIndexByAreaFilter
);
2116 // --- execute search
2117 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
2119 // --- initialize taxa, highlight matches ....
2120 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
2123 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
2124 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
2126 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
2127 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
2131 * @param namedAreaList at least one area must be in the list
2132 * @param distributionStatusList optional
2134 * @throws IOException
2136 protected Query
createByDistributionJoinQuery(
2137 List
<NamedArea
> namedAreaList
,
2138 List
<PresenceAbsenceTerm
> distributionStatusList
,
2139 QueryFactory queryFactory
2140 ) throws IOException
{
2142 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
2143 String toField
= "id"; // id in TaxonBase index
2145 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, queryFactory
);
2147 Query taxonAreaJoinQuery
= queryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
2149 return taxonAreaJoinQuery
;
2153 * @param namedAreaList
2154 * @param distributionStatusList
2155 * @param queryFactory
2158 private BooleanQuery
createByDistributionQuery(List
<NamedArea
> namedAreaList
,
2159 List
<PresenceAbsenceTerm
> distributionStatusList
, QueryFactory queryFactory
) {
2160 BooleanQuery areaQuery
= new BooleanQuery();
2161 // area field from Distribution
2162 areaQuery
.add(queryFactory
.newEntityIdsQuery("area.id", namedAreaList
), Occur
.MUST
);
2164 // status field from Distribution
2165 if(distributionStatusList
!= null && distributionStatusList
.size() > 0){
2166 areaQuery
.add(queryFactory
.newEntityIdsQuery("status.id", distributionStatusList
), Occur
.MUST
);
2169 logger
.debug("createByDistributionQuery() query: " + areaQuery
.toString());
2174 * This method has been primarily created for testing the area join query but might
2175 * also be useful in other situations
2177 * @param namedAreaList
2178 * @param distributionStatusList
2179 * @param classification
2180 * @param highlightFragments
2182 * @throws IOException
2184 protected LuceneSearch
prepareByDistributionSearch(
2185 List
<NamedArea
> namedAreaList
, List
<PresenceAbsenceTerm
> distributionStatusList
,
2186 Classification classification
) throws IOException
{
2188 BooleanQuery finalQuery
= new BooleanQuery();
2190 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
2192 // FIXME is this query factory using the wrong type?
2193 QueryFactory taxonQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Taxon
.class);
2195 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
2196 luceneSearch
.setSortFields(sortFields
);
2199 Query byAreaQuery
= createByDistributionJoinQuery(namedAreaList
, distributionStatusList
, taxonQueryFactory
);
2201 finalQuery
.add(byAreaQuery
, Occur
.MUST
);
2203 if(classification
!= null){
2204 finalQuery
.add(taxonQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
2207 logger
.info("prepareByAreaSearch() query: " + finalQuery
.toString());
2208 luceneSearch
.setQuery(finalQuery
);
2210 return luceneSearch
;
2216 * @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)
2219 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
2220 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
2221 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
2222 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
2225 LuceneSearch luceneSearch
= prepareByDescriptionElementFullTextSearch(clazz
, queryString
, classification
, features
, languages
, highlightFragments
);
2227 // --- execute search
2228 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
2230 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
2231 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
2233 // --- initialize taxa, highlight matches ....
2234 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
2235 @SuppressWarnings("rawtypes")
2236 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
2237 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
2239 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
2240 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
2246 public Pager
<SearchResult
<TaxonBase
>> findByEverythingFullText(String queryString
,
2247 Classification classification
, List
<Language
> languages
, boolean highlightFragments
,
2248 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
2250 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, null, languages
, highlightFragments
);
2251 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
, null);
2253 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
, luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
2255 // --- execute search
2256 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
2258 // --- initialize taxa, highlight matches ....
2259 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
2261 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
2262 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
2263 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
2265 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
2266 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
2268 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
2269 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
2276 * @param queryString
2277 * @param classification
2280 * @param highlightFragments
2281 * @param directorySelectClass
2284 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
,
2285 String queryString
, Classification classification
, List
<Feature
> features
,
2286 List
<Language
> languages
, boolean highlightFragments
) {
2288 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, DescriptionElementBase
.class);
2289 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
2291 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", SortField
.STRING
, false)};
2293 BooleanQuery finalQuery
= createByDescriptionElementFullTextQuery(queryString
, classification
, features
,
2294 languages
, descriptionElementQueryFactory
);
2296 luceneSearch
.setSortFields(sortFields
);
2297 luceneSearch
.setCdmTypRestriction(clazz
);
2298 luceneSearch
.setQuery(finalQuery
);
2299 if(highlightFragments
){
2300 luceneSearch
.setHighlightFields(descriptionElementQueryFactory
.getTextFieldNamesAsArray());
2303 return luceneSearch
;
2307 * @param queryString
2308 * @param classification
2311 * @param descriptionElementQueryFactory
2314 private BooleanQuery
createByDescriptionElementFullTextQuery(String queryString
, Classification classification
,
2315 List
<Feature
> features
, List
<Language
> languages
, QueryFactory descriptionElementQueryFactory
) {
2316 BooleanQuery finalQuery
= new BooleanQuery();
2317 BooleanQuery textQuery
= new BooleanQuery();
2318 textQuery
.add(descriptionElementQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
2322 if(languages
== null || languages
.size() == 0){
2323 nameQuery
= descriptionElementQueryFactory
.newTermQuery("name", queryString
);
2325 nameQuery
= new BooleanQuery();
2326 BooleanQuery languageSubQuery
= new BooleanQuery();
2327 for(Language lang
: languages
){
2328 languageSubQuery
.add(descriptionElementQueryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString(), false), Occur
.SHOULD
);
2330 ((BooleanQuery
) nameQuery
).add(descriptionElementQueryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
2331 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
2333 textQuery
.add(nameQuery
, Occur
.SHOULD
);
2336 // text field from TextData
2337 textQuery
.add(descriptionElementQueryFactory
.newMultilanguageTextQuery("text", queryString
, languages
), Occur
.SHOULD
);
2339 // --- TermBase fields - by representation ----
2340 // state field from CategoricalData
2341 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("stateData.state", queryString
, languages
), Occur
.SHOULD
);
2343 // state field from CategoricalData
2344 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("stateData.modifyingText", queryString
, languages
), Occur
.SHOULD
);
2346 // area field from Distribution
2347 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("area", queryString
, languages
), Occur
.SHOULD
);
2349 // status field from Distribution
2350 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("status", queryString
, languages
), Occur
.SHOULD
);
2352 finalQuery
.add(textQuery
, Occur
.MUST
);
2353 // --- classification ----
2355 if(classification
!= null){
2356 finalQuery
.add(descriptionElementQueryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
2359 // --- IdentifieableEntity fields - by uuid
2360 if(features
!= null && features
.size() > 0 ){
2361 finalQuery
.add(descriptionElementQueryFactory
.newEntityUuidsQuery("feature.uuid", features
), Occur
.MUST
);
2364 // the description must be associated with a taxon
2365 finalQuery
.add(descriptionElementQueryFactory
.newIsNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
2367 logger
.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery
.toString());
2372 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
2373 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
2374 * This method is a convenient means to retrieve a Lucene query string for such the fields.
2376 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
2377 * or {@link MultilanguageTextFieldBridge }
2378 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
2379 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
2380 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
2382 * TODO move to utiliy class !!!!!!!!
2384 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
2386 if(stringBuilder
== null){
2387 stringBuilder
= new StringBuilder();
2389 if(languages
== null || languages
.size() == 0){
2390 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
2392 for(Language lang
: languages
){
2393 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
2396 return stringBuilder
;
2400 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
2401 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2402 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
2404 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
2407 UUID nameUuid
= taxon
.getName().getUuid();
2408 ZoologicalName taxonName
= getZoologicalName(nameUuid
, zooHashMap
);
2409 String epithetOfTaxon
= null;
2410 String infragenericEpithetOfTaxon
= null;
2411 String infraspecificEpithetOfTaxon
= null;
2412 if (taxonName
.isSpecies()){
2413 epithetOfTaxon
= taxonName
.getSpecificEpithet();
2414 } else if (taxonName
.isInfraGeneric()){
2415 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
2416 } else if (taxonName
.isInfraSpecific()){
2417 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
2419 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
2420 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
2421 List
<String
> taxonNames
= new ArrayList
<String
>();
2423 for (TaxonNode node
: nodes
){
2424 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
2425 // List<String> synonymsEpithet = new ArrayList<String>();
2427 if (node
.getClassification().equals(classification
)){
2428 if (!node
.isTopmostNode()){
2429 TaxonNode parent
= node
.getParent();
2430 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
2431 TaxonNameBase
<?
,?
> parentName
= parent
.getTaxon().getName();
2432 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
2433 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
2434 Rank rankOfTaxon
= taxonName
.getRank();
2437 //create inferred synonyms for species, subspecies
2438 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
2440 Synonym inferredEpithet
= null;
2441 Synonym inferredGenus
= null;
2442 Synonym potentialCombination
= null;
2444 List
<String
> propertyPaths
= new ArrayList
<String
>();
2445 propertyPaths
.add("synonym");
2446 propertyPaths
.add("synonym.name");
2447 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
2448 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
2450 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2451 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2453 List
<TaxonRelationship
> taxonRelListParent
= null;
2454 List
<TaxonRelationship
> taxonRelListTaxon
= null;
2455 if (doWithMisappliedNames
){
2456 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2457 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2461 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
2464 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2465 Synonym syn
= synonymRelationOfParent
.getSynonym();
2467 inferredEpithet
= createInferredEpithets(taxon
,
2468 zooHashMap
, taxonName
, epithetOfTaxon
,
2469 infragenericEpithetOfTaxon
,
2470 infraspecificEpithetOfTaxon
,
2471 taxonNames
, parentName
,
2475 inferredSynonyms
.add(inferredEpithet
);
2476 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2477 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2480 if (doWithMisappliedNames
){
2482 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
2483 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2485 inferredEpithet
= createInferredEpithets(taxon
,
2486 zooHashMap
, taxonName
, epithetOfTaxon
,
2487 infragenericEpithetOfTaxon
,
2488 infraspecificEpithetOfTaxon
,
2489 taxonNames
, parentName
,
2492 inferredSynonyms
.add(inferredEpithet
);
2493 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2494 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2498 if (!taxonNames
.isEmpty()){
2499 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2500 ZoologicalName name
;
2501 if (!synNotInCDM
.isEmpty()){
2502 inferredSynonymsToBeRemoved
.clear();
2504 for (Synonym syn
:inferredSynonyms
){
2505 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2506 if (!synNotInCDM
.contains(name
.getNameCache())){
2507 inferredSynonymsToBeRemoved
.add(syn
);
2511 // Remove identified Synonyms from inferredSynonyms
2512 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2513 inferredSynonyms
.remove(synonym
);
2518 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
2521 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2522 TaxonNameBase synName
;
2523 ZoologicalName inferredSynName
;
2525 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2526 inferredGenus
= createInferredGenus(taxon
,
2527 zooHashMap
, taxonName
, epithetOfTaxon
,
2528 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
2530 inferredSynonyms
.add(inferredGenus
);
2531 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2532 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2537 if (doWithMisappliedNames
){
2539 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2540 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2541 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
2543 inferredSynonyms
.add(inferredGenus
);
2544 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2545 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2550 if (!taxonNames
.isEmpty()){
2551 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2552 ZoologicalName name
;
2553 if (!synNotInCDM
.isEmpty()){
2554 inferredSynonymsToBeRemoved
.clear();
2556 for (Synonym syn
:inferredSynonyms
){
2557 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2558 if (!synNotInCDM
.contains(name
.getNameCache())){
2559 inferredSynonymsToBeRemoved
.add(syn
);
2563 // Remove identified Synonyms from inferredSynonyms
2564 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2565 inferredSynonyms
.remove(synonym
);
2570 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
2572 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
2573 ZoologicalName inferredSynName
;
2574 //for all synonyms of the parent...
2575 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2576 TaxonNameBase synName
;
2577 Synonym synParent
= synonymRelationOfParent
.getSynonym();
2578 synName
= synParent
.getName();
2580 HibernateProxyHelper
.deproxy(synParent
);
2582 // Set the sourceReference
2583 sourceReference
= synParent
.getSec();
2585 // Determine the idInSource
2586 String idInSourceParent
= getIdInSource(synParent
);
2588 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2589 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2590 String synParentInfragenericName
= null;
2591 String synParentSpecificEpithet
= null;
2593 if (parentSynZooName
.isInfraGeneric()){
2594 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2596 if (parentSynZooName
.isSpecies()){
2597 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2600 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2601 synonymsGenus.put(synGenusName, idInSource);
2604 //for all synonyms of the taxon
2606 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2608 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2609 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2610 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
2612 synParentInfragenericName
,
2613 synParentSpecificEpithet
, syn
, zooHashMap
);
2615 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2616 inferredSynonyms
.add(potentialCombination
);
2617 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2618 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2625 if (doWithMisappliedNames
){
2627 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
2629 TaxonNameBase misappliedParentName
;
2631 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
2632 misappliedParentName
= misappliedParent
.getName();
2634 HibernateProxyHelper
.deproxy(misappliedParent
);
2636 // Set the sourceReference
2637 sourceReference
= misappliedParent
.getSec();
2639 // Determine the idInSource
2640 String idInSourceParent
= getIdInSource(misappliedParent
);
2642 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
2643 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2644 String synParentInfragenericName
= null;
2645 String synParentSpecificEpithet
= null;
2647 if (parentSynZooName
.isInfraGeneric()){
2648 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2650 if (parentSynZooName
.isSpecies()){
2651 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2655 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2656 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2657 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
2658 potentialCombination
= createPotentialCombination(
2659 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
2661 synParentInfragenericName
,
2662 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
2665 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2666 inferredSynonyms
.add(potentialCombination
);
2667 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2668 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2673 if (!taxonNames
.isEmpty()){
2674 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2675 ZoologicalName name
;
2676 if (!synNotInCDM
.isEmpty()){
2677 inferredSynonymsToBeRemoved
.clear();
2678 for (Synonym syn
:inferredSynonyms
){
2680 name
= (ZoologicalName
) syn
.getName();
2681 }catch (ClassCastException e
){
2682 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2684 if (!synNotInCDM
.contains(name
.getNameCache())){
2685 inferredSynonymsToBeRemoved
.add(syn
);
2688 // Remove identified Synonyms from inferredSynonyms
2689 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2690 inferredSynonyms
.remove(synonym
);
2696 logger
.info("The synonymrelationship type is not defined.");
2697 return inferredSynonyms
;
2704 return inferredSynonyms
;
2707 private Synonym
createPotentialCombination(String idInSourceParent
,
2708 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
2709 String synParentInfragenericName
, String synParentSpecificEpithet
,
2710 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2711 Synonym potentialCombination
;
2712 Reference sourceReference
;
2713 ZoologicalName inferredSynName
;
2714 HibernateProxyHelper
.deproxy(syn
);
2716 // Set sourceReference
2717 sourceReference
= syn
.getSec();
2718 if (sourceReference
== null){
2719 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2721 if (!parentSynZooName
.getTaxa().isEmpty()){
2722 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
2724 sourceReference
= taxon
.getSec();
2727 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
2729 String synTaxonInfraSpecificName
= null;
2731 if (parentSynZooName
.isSpecies()){
2732 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
2735 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
2736 synonymsEpithet.add(epithetName);
2739 //create potential combinations...
2740 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
2742 inferredSynName
.setGenusOrUninomial(synParentGenus
);
2743 if (zooSynName
.isSpecies()){
2744 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
2745 if (parentSynZooName
.isInfraGeneric()){
2746 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2749 if (zooSynName
.isInfraSpecific()){
2750 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
2751 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
2753 if (parentSynZooName
.isInfraGeneric()){
2754 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2758 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
2760 // Set the sourceReference
2761 potentialCombination
.setSec(sourceReference
);
2764 // Determine the idInSource
2765 String idInSourceSyn
= getIdInSource(syn
);
2767 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
2768 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
, idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2769 inferredSynName
.addSource(originalSource
);
2770 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
, idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2771 potentialCombination
.addSource(originalSource
);
2774 return potentialCombination
;
2777 private Synonym
createInferredGenus(Taxon taxon
,
2778 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2779 String epithetOfTaxon
, String genusOfTaxon
,
2780 List
<String
> taxonNames
, ZoologicalName zooParentName
,
2783 Synonym inferredGenus
;
2784 TaxonNameBase synName
;
2785 ZoologicalName inferredSynName
;
2786 synName
=syn
.getName();
2787 HibernateProxyHelper
.deproxy(syn
);
2789 // Determine the idInSource
2790 String idInSourceSyn
= getIdInSource(syn
);
2791 String idInSourceTaxon
= getIdInSource(taxon
);
2792 // Determine the sourceReference
2793 Reference sourceReference
= syn
.getSec();
2795 //logger.warn(sourceReference.getTitleCache());
2797 synName
= syn
.getName();
2798 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2799 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
2800 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
2801 synonymsEpithet.add(synSpeciesEpithetName);
2804 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2805 //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...
2808 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
2809 if (zooParentName
.isInfraGeneric()){
2810 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
2813 if (taxonName
.isSpecies()){
2814 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
2816 if (taxonName
.isInfraSpecific()){
2817 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2818 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
2822 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
2824 // Set the sourceReference
2825 inferredGenus
.setSec(sourceReference
);
2827 // Add the original source
2828 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
2829 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2830 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2831 inferredGenus
.addSource(originalSource
);
2833 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2834 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2835 inferredSynName
.addSource(originalSource
);
2836 originalSource
= null;
2839 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
2840 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2841 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2842 inferredGenus
.addSource(originalSource
);
2844 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2845 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2846 inferredSynName
.addSource(originalSource
);
2847 originalSource
= null;
2850 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
2852 return inferredGenus
;
2855 private Synonym
createInferredEpithets(Taxon taxon
,
2856 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2857 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
2858 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
2859 TaxonNameBase parentName
, TaxonBase syn
) {
2861 Synonym inferredEpithet
;
2862 TaxonNameBase
<?
,?
> synName
;
2863 ZoologicalName inferredSynName
;
2864 HibernateProxyHelper
.deproxy(syn
);
2866 // Determine the idInSource
2867 String idInSourceSyn
= getIdInSource(syn
);
2868 String idInSourceTaxon
= getIdInSource(taxon
);
2869 // Determine the sourceReference
2870 Reference
<?
> sourceReference
= syn
.getSec();
2872 if (sourceReference
== null){
2873 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
2874 sourceReference
= taxon
.getSec();
2877 synName
= syn
.getName();
2878 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2879 String synGenusName
= zooSynName
.getGenusOrUninomial();
2880 String synInfraGenericEpithet
= null;
2881 String synSpecificEpithet
= null;
2883 if (zooSynName
.getInfraGenericEpithet() != null){
2884 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
2887 if (zooSynName
.isInfraSpecific()){
2888 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
2891 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2892 synonymsGenus.put(synGenusName, idInSource);
2895 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2897 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
2898 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
2899 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
2901 inferredSynName
.setGenusOrUninomial(synGenusName
);
2903 if (parentName
.isInfraGeneric()){
2904 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
2906 if (taxonName
.isSpecies()){
2907 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2908 }else if (taxonName
.isInfraSpecific()){
2909 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
2910 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
2913 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
2915 // Set the sourceReference
2916 inferredEpithet
.setSec(sourceReference
);
2918 /* Add the original source
2919 if (idInSource != null) {
2920 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
2923 Reference citation = getCitation(syn);
2924 if (citation != null) {
2925 originalSource.setCitation(citation);
2926 inferredEpithet.addSource(originalSource);
2929 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
2932 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2933 taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2935 inferredEpithet
.addSource(originalSource
);
2937 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2938 taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2940 inferredSynName
.addSource(originalSource
);
2944 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
2946 return inferredEpithet
;
2950 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
2951 * Very likely only useful for createInferredSynonyms().
2956 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2957 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
2958 if (taxonName
== null) {
2959 taxonName
= zooHashMap
.get(uuid
);
2965 * Returns the idInSource for a given Synonym.
2968 private String
getIdInSource(TaxonBase taxonBase
) {
2969 String idInSource
= null;
2970 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
2971 if (sources
.size() == 1) {
2972 IdentifiableSource source
= sources
.iterator().next();
2973 if (source
!= null) {
2974 idInSource
= source
.getIdInSource();
2976 } else if (sources
.size() > 1) {
2979 for (IdentifiableSource source
: sources
) {
2980 idInSource
+= source
.getIdInSource();
2981 if (count
< sources
.size()) {
2986 } else if (sources
.size() == 0){
2987 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
2996 * Returns the citation for a given Synonym.
2999 private Reference
getCitation(Synonym syn
) {
3000 Reference citation
= null;
3001 Set
<IdentifiableSource
> sources
= syn
.getSources();
3002 if (sources
.size() == 1) {
3003 IdentifiableSource source
= sources
.iterator().next();
3004 if (source
!= null) {
3005 citation
= source
.getCitation();
3007 } else if (sources
.size() > 1) {
3008 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
3015 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
3016 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
3018 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
3019 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
3020 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
3022 return inferredSynonyms
;
3026 public List
<Classification
> listClassifications(TaxonBase taxonBase
, Integer limit
, Integer start
, List
<String
> propertyPaths
) {
3028 // TODO quickly implemented, create according dao !!!!
3029 Set
<TaxonNode
> nodes
= new HashSet
<TaxonNode
>();
3030 Set
<Classification
> classifications
= new HashSet
<Classification
>();
3031 List
<Classification
> list
= new ArrayList
<Classification
>();
3033 if (taxonBase
== null) {
3037 taxonBase
= load(taxonBase
.getUuid());
3039 if (taxonBase
instanceof Taxon
) {
3040 nodes
.addAll(((Taxon
)taxonBase
).getTaxonNodes());
3042 for (Taxon taxon
: ((Synonym
)taxonBase
).getAcceptedTaxa() ) {
3043 nodes
.addAll(taxon
.getTaxonNodes());
3046 for (TaxonNode node
: nodes
) {
3047 classifications
.add(node
.getClassification());
3049 list
.addAll(classifications
);
3054 public Synonym
changeRelatedTaxonToSynonym(Taxon fromTaxon
, Taxon toTaxon
, TaxonRelationshipType oldRelationshipType
,
3055 SynonymRelationshipType synonymRelationshipType
) throws DataChangeNoRollbackException
{
3056 // Create new synonym using concept name
3057 TaxonNameBase
<?
, ?
> synonymName
= fromTaxon
.getName();
3058 Synonym synonym
= Synonym
.NewInstance(synonymName
, fromTaxon
.getSec());
3060 // Remove concept relation from taxon
3061 toTaxon
.removeTaxon(fromTaxon
, oldRelationshipType
);
3066 // Create a new synonym for the taxon
3067 SynonymRelationship synonymRelationship
;
3068 if (synonymRelationshipType
!= null
3069 && synonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF())){
3070 synonymRelationship
= toTaxon
.addHomotypicSynonym(synonym
, null, null);
3072 synonymRelationship
= toTaxon
.addHeterotypicSynonymName(synonymName
);
3075 this.saveOrUpdate(toTaxon
);
3076 //TODO: configurator and classification
3077 TaxonDeletionConfigurator config
= new TaxonDeletionConfigurator();
3078 config
.setDeleteNameIfPossible(false);
3079 this.deleteTaxon(fromTaxon
, config
, null);
3080 return synonymRelationship
.getSynonym();
3084 public DeleteResult
isDeletable(TaxonBase taxonBase
, DeleteConfiguratorBase config
){
3085 DeleteResult result
= new DeleteResult();
3086 Set
<CdmBase
> references
= commonService
.getReferencingObjectsForDeletion(taxonBase
);
3087 if (taxonBase
instanceof Taxon
){
3088 TaxonDeletionConfigurator taxonConfig
= (TaxonDeletionConfigurator
) config
;
3089 result
= isDeletableForTaxon(references
, taxonConfig
);
3091 SynonymDeletionConfigurator synonymConfig
= (SynonymDeletionConfigurator
) config
;
3092 result
= isDeletableForSynonym(references
, synonymConfig
);
3097 private DeleteResult
isDeletableForSynonym(Set
<CdmBase
> references
, SynonymDeletionConfigurator config
){
3099 DeleteResult result
= new DeleteResult();
3100 for (CdmBase ref
: references
){
3101 if (!(ref
instanceof SynonymRelationship
|| ref
instanceof Taxon
|| ref
instanceof TaxonNameBase
)){
3102 message
= "The Synonym can't be deleted as long as it is referenced by " + ref
.getClass().getSimpleName() + " with id "+ ref
.getId();
3103 result
.addException(new ReferencedObjectUndeletableException(message
));
3104 result
.addRelatedObject(ref
);
3111 private DeleteResult
isDeletableForTaxon(Set
<CdmBase
> references
, TaxonDeletionConfigurator config
){
3112 String message
= null;
3113 DeleteResult result
= new DeleteResult();
3114 for (CdmBase ref
: references
){
3115 if (!(ref
instanceof TaxonNameBase
)){
3116 if (!config
.isDeleteSynonymRelations() && (ref
instanceof SynonymRelationship
)){
3117 message
= "The Taxon can't be deleted as long as it has synonyms.";
3120 if (!config
.isDeleteDescriptions() && (ref
instanceof DescriptionBase
)){
3121 message
= "The Taxon can't be deleted as long as it has factual data.";
3125 if (!config
.isDeleteTaxonNodes() && (ref
instanceof TaxonNode
)){
3126 message
= "The Taxon can't be deleted as long as it belongs to a taxon node.";
3129 if (!config
.isDeleteTaxonRelationships() && (ref
instanceof TaxonNode
)){
3130 if (!config
.isDeleteMisappliedNamesAndInvalidDesignations() && (((TaxonRelationship
)ref
).getType().equals(TaxonRelationshipType
.MISAPPLIED_NAME_FOR())|| ((TaxonRelationship
)ref
).getType().equals(TaxonRelationshipType
.INVALID_DESIGNATION_FOR()))){
3131 message
= "The Taxon can't be deleted as long as it has misapplied names or invalid designations.";
3134 message
= "The Taxon can't be deleted as long as it belongs to a taxon node.";
3138 if (ref
instanceof PolytomousKeyNode
){
3139 message
= "The Taxon can't be deleted as long as it is referenced by a polytomous key node.";
3143 if (HibernateProxyHelper
.isInstanceOf(ref
, IIdentificationKey
.class)){
3144 message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
3150 /* //PolytomousKeyNode
3151 if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){
3152 String message = "Taxon" + taxon.getTitleCache() + " can't be deleted as it is used in polytomous key node";
3157 if (ref
.isInstanceOf(TaxonInteraction
.class)){
3158 message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
3163 if (ref
.isInstanceOf(DeterminationEvent
.class)){
3164 message
= "Taxon can't be deleted as it is used in a determination event";
3169 if (message
!= null){
3170 result
.addException(new ReferencedObjectUndeletableException(message
));
3171 result
.addRelatedObject(ref
);
3180 public IncludedTaxaDTO
listIncludedTaxa(UUID taxonUuid
, IncludedTaxonConfiguration config
) {
3181 IncludedTaxaDTO result
= new IncludedTaxaDTO(taxonUuid
);
3183 //preliminary implementation
3185 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
3186 TaxonBase taxonBase
= find(taxonUuid
);
3187 if (taxonBase
== null){
3188 return new IncludedTaxaDTO();
3189 }else if (taxonBase
.isInstanceOf(Taxon
.class)){
3190 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
3192 }else if (taxonBase
.isInstanceOf(Synonym
.class)){
3193 //TODO partial synonyms ??
3194 //TODO synonyms in general
3195 Synonym syn
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
3196 taxa
.addAll(syn
.getAcceptedTaxa());
3198 throw new IllegalArgumentException("Unhandled class " + taxonBase
.getClass().getSimpleName());
3201 Set
<Taxon
> related
= makeRelatedIncluded(taxa
, result
, config
);
3203 while((! related
.isEmpty()) && i
++ < 100){ //to avoid
3204 related
= makeRelatedIncluded(related
, result
, config
);
3211 * Computes all children and conceptually congruent and included taxa and adds them to the existingTaxa
3213 * @return the set of conceptually related taxa for further use
3216 * @param uncheckedTaxa
3217 * @param existingTaxa
3221 private Set
<Taxon
> makeRelatedIncluded(Set
<Taxon
> uncheckedTaxa
, IncludedTaxaDTO existingTaxa
, IncludedTaxonConfiguration config
) {
3224 Set
<TaxonNode
> taxonNodes
= new HashSet
<TaxonNode
>();
3225 for (Taxon taxon
: uncheckedTaxa
){
3226 taxonNodes
.addAll(taxon
.getTaxonNodes());
3229 Set
<Taxon
> children
= new HashSet
<Taxon
>();
3230 if (! config
.onlyCongruent
){
3231 for (TaxonNode node
: taxonNodes
){
3232 List
<TaxonNode
> childNodes
= nodeService
.loadChildNodesOfTaxonNode(node
, null, true, false);
3233 for (TaxonNode child
: childNodes
){
3234 children
.add(child
.getTaxon());
3237 children
.remove(null); // just to be on the save side
3240 Iterator
<Taxon
> it
= children
.iterator();
3241 while(it
.hasNext()){
3242 UUID uuid
= it
.next().getUuid();
3243 if (existingTaxa
.contains(uuid
)){
3246 existingTaxa
.addIncludedTaxon(uuid
, new ArrayList
<UUID
>(), false);
3251 Set
<Taxon
> uncheckedAndChildren
= new HashSet
<Taxon
>(uncheckedTaxa
);
3252 uncheckedAndChildren
.addAll(children
);
3254 Set
<Taxon
> relatedTaxa
= makeConceptIncludedTaxa(uncheckedAndChildren
, existingTaxa
, config
);
3257 Set
<Taxon
> result
= new HashSet
<Taxon
>(relatedTaxa
);
3262 * Computes all conceptually congruent or included taxa and adds them to the existingTaxa data structure.
3263 * @return the set of these computed taxa
3265 private Set
<Taxon
> makeConceptIncludedTaxa(Set
<Taxon
> unchecked
, IncludedTaxaDTO existingTaxa
, IncludedTaxonConfiguration config
) {
3266 Set
<Taxon
> result
= new HashSet
<Taxon
>();
3268 for (Taxon taxon
: unchecked
){
3269 Set
<TaxonRelationship
> fromRelations
= taxon
.getRelationsFromThisTaxon();
3270 Set
<TaxonRelationship
> toRelations
= taxon
.getRelationsToThisTaxon();
3272 for (TaxonRelationship fromRel
: fromRelations
){
3273 if (config
.includeDoubtful
== false && fromRel
.isDoubtful()){
3276 if (fromRel
.getType().equals(TaxonRelationshipType
.CONGRUENT_TO()) ||
3277 !config
.onlyCongruent
&& fromRel
.getType().equals(TaxonRelationshipType
.INCLUDES()) ||
3278 !config
.onlyCongruent
&& fromRel
.getType().equals(TaxonRelationshipType
.CONGRUENT_OR_INCLUDES())
3280 result
.add(fromRel
.getToTaxon());
3284 for (TaxonRelationship toRel
: toRelations
){
3285 if (config
.includeDoubtful
== false && toRel
.isDoubtful()){
3288 if (toRel
.getType().equals(TaxonRelationshipType
.CONGRUENT_TO())){
3289 result
.add(toRel
.getFromTaxon());
3294 Iterator
<Taxon
> it
= result
.iterator();
3295 while(it
.hasNext()){
3296 UUID uuid
= it
.next().getUuid();
3297 if (existingTaxa
.contains(uuid
)){
3300 existingTaxa
.addIncludedTaxon(uuid
, new ArrayList
<UUID
>(), false);
3306 public List
<TaxonBase
> findTaxaByName(MatchingTaxonConfigurator config
){
3307 List
<TaxonBase
> taxonList
= dao
.getTaxaByName(true, false, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, 0, config
.getPropertyPath());