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
.PresenceAbsenceTermBase
;
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
.DnaSample
;
96 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
97 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
98 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
99 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
100 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
101 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
102 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
103 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
104 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
105 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
106 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
107 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
108 import eu
.etaxonomy
.cdm
.model
.taxon
.ITaxonTreeNode
;
109 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
110 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
111 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
112 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
113 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
114 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
115 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
116 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
117 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
118 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
119 import eu
.etaxonomy
.cdm
.persistence
.dao
.initializer
.AbstractBeanInitializer
;
120 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
121 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
122 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.IClassificationDao
;
123 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
124 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
125 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
126 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
127 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
128 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
132 * @author a.kohlbecker
137 @Transactional(readOnly
= true)
138 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
139 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
141 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
143 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
145 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
149 private ITaxonNameDao nameDao
;
152 private INameService nameService
;
155 private ITaxonNodeService nodeService
;
158 private ICdmGenericDao genericDao
;
161 private IDescriptionService descriptionService
;
164 private IOrderedTermVocabularyDao orderedVocabularyDao
;
167 private IOccurrenceDao occurrenceDao
;
170 private IClassificationDao classificationDao
;
173 private AbstractBeanInitializer beanInitializer
;
176 private ILuceneIndexToolProvider luceneIndexToolProvider
;
181 public TaxonServiceImpl(){
182 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
186 * FIXME Candidate for harmonization
187 * rename searchByName ?
190 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
191 return dao
.getTaxaByName(name
, sec
);
195 * FIXME Candidate for harmonization
196 * merge with getRootTaxa(Reference sec, ..., ...)
198 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
201 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
202 if (cdmFetch
== null){
203 cdmFetch
= CdmFetch
.NO_FETCH();
205 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
209 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
210 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
214 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
215 return dao
.getAllRelationships(limit
, start
);
219 * FIXME Candidate for harmonization
220 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
224 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
226 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
227 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
228 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
229 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
230 return taxonRelTypeVocabulary
;
237 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
240 @Transactional(readOnly
= false)
241 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
243 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
244 synonymName
.removeTaxonBase(synonym
);
245 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
246 taxonName
.removeTaxonBase(acceptedTaxon
);
248 synonym
.setName(taxonName
);
249 acceptedTaxon
.setName(synonymName
);
251 // the accepted taxon needs a new uuid because the concept has changed
252 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
253 //acceptedTaxon.setUuid(UUID.randomUUID());
258 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
262 @Transactional(readOnly
= false)
263 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
265 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
266 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
267 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
269 //check synonym is not homotypic
270 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
271 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
272 throw new HomotypicalGroupChangeException(message
);
275 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
277 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
278 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
279 Set
<NameRelationship
> basionymsAndReplacedSynonyms
= synonymHomotypicGroup
.getBasionymAndReplacedSynonymRelations();
281 for (Synonym heteroSynonym
: heteroSynonyms
){
282 if (synonym
.equals(heteroSynonym
)){
283 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
286 //move synonyms in same homotypic group to new accepted taxon
287 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
291 //synonym.getName().removeTaxonBase(synonym);
294 // deleteSynonym(synonym, taxon, false);
297 SynonymDeletionConfigurator config
= new SynonymDeletionConfigurator();
298 config
.setDeleteNameIfPossible(false);
299 this.deleteSynonym(synonym
, acceptedTaxon
, config
);
301 } catch (Exception e
) {
302 logger
.info("Can't delete old synonym from database");
306 return newAcceptedTaxon
;
311 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
313 // Get name from synonym
314 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
316 /* // remove synonym from taxon
317 toTaxon.removeSynonym(synonym);
319 // Create a taxon with synonym name
320 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
322 // Add taxon relation
323 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
325 // since we are swapping names, we have to detach the name from the synonym completely.
326 // Otherwise the synonym will still be in the list of typified names.
327 // synonym.getName().removeTaxonBase(synonym);
328 this.deleteSynonym(synonym
, null);
335 * @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)
337 @Transactional(readOnly
= false)
339 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
340 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
342 TaxonNameBase synonymName
= synonym
.getName();
343 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
347 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
348 newHomotypicalGroup
.addTypifiedName(synonymName
);
350 //remove existing basionym relationships
351 synonymName
.removeBasionyms();
353 //add basionym relationship
354 if (setBasionymRelationIfApplicable
){
355 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
356 for (TaxonNameBase basionym
: basionyms
){
357 synonymName
.addBasionym(basionym
);
361 //set synonym relationship correctly
362 // SynonymRelationship relToTaxon = null;
363 boolean relToTargetTaxonExists
= false;
364 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
365 for (SynonymRelationship rel
: existingRelations
){
366 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
367 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
368 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
369 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
370 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
371 rel
.setType(newRelationType
);
372 //TODO handle citation and microCitation
375 relToTargetTaxonExists
= true;
377 if (removeFromOtherTaxa
){
378 acceptedTaxon
.removeSynonym(synonym
, false);
384 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
385 Taxon acceptedTaxon
= targetTaxon
;
386 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
387 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
388 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
389 //TODO handle citation and microCitation
390 Reference citation
= null;
391 String microCitation
= null;
392 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
399 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
402 @Transactional(readOnly
= false)
403 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
405 clazz
= TaxonBase
.class;
407 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
412 protected void setDao(ITaxonDao dao
) {
417 * @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)
420 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
421 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
423 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
424 if(numberOfResults
> 0) { // no point checking again
425 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
428 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
432 * @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)
435 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
436 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
438 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
439 if(numberOfResults
> 0) { // no point checking again
440 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
447 * @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)
450 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
451 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
453 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
454 if(numberOfResults
> 0) { // no point checking again
455 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
461 * @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)
464 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
465 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
467 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
468 if(numberOfResults
> 0) { // no point checking again
469 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
471 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
475 * @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)
478 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
479 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
481 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
482 if(numberOfResults
> 0) { // no point checking again
483 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
489 * @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)
492 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
493 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
495 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
496 if(numberOfResults
> 0) { // no point checking again
497 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
499 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
503 public List
<Taxon
> listAcceptedTaxaFor(UUID synonymUuid
, UUID classificationUuid
, Integer pageSize
, Integer pageNumber
,
504 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
505 return pageAcceptedTaxaFor(synonymUuid
, classificationUuid
, pageSize
, pageNumber
, orderHints
, propertyPaths
).getRecords();
509 public Pager
<Taxon
> pageAcceptedTaxaFor(UUID synonymUuid
, UUID classificationUuid
, Integer pageSize
, Integer pageNumber
,
510 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
512 List
<Taxon
> list
= new ArrayList
<Taxon
>();
515 Synonym synonym
= null;
518 synonym
= (Synonym
) dao
.load(synonymUuid
);
519 } catch (ClassCastException e
){
520 throw new EntityNotFoundException("The TaxonBase entity referenced by " + synonymUuid
+ " is not a Synonmy");
521 } catch (NullPointerException e
){
522 throw new EntityNotFoundException("No TaxonBase entity found for " + synonymUuid
);
525 Classification classificationFilter
= null;
526 if(classificationUuid
!= null){
528 classificationFilter
= classificationDao
.load(classificationUuid
);
529 } catch (NullPointerException e
){
530 throw new EntityNotFoundException("No Classification entity found for " + classificationUuid
);
532 if(classificationFilter
== null){
537 count
= dao
.countAcceptedTaxaFor(synonym
, classificationFilter
) ;
538 if(count
> (pageSize
* pageNumber
)){
539 list
= dao
.listAcceptedTaxaFor(synonym
, classificationFilter
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
542 return new DefaultPagerImpl
<Taxon
>(pageNumber
, count
.intValue(), pageSize
, list
);
548 * @param includeRelationships
552 * @param propertyPaths
553 * @return an List which is not specifically ordered
556 public Set
<Taxon
> listRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Integer maxDepth
,
557 Integer limit
, Integer start
, List
<String
> propertyPaths
) {
559 Set
<Taxon
> relatedTaxa
= collectRelatedTaxa(taxon
, includeRelationships
, new HashSet
<Taxon
>(), maxDepth
);
560 relatedTaxa
.remove(taxon
);
561 beanInitializer
.initializeAll(relatedTaxa
, propertyPaths
);
567 * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the
568 * <code>taxon</code> supplied as parameter.
571 * @param includeRelationships
573 * @param maxDepth can be <code>null</code> for infinite depth
576 private Set
<Taxon
> collectRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Set
<Taxon
> taxa
, Integer maxDepth
) {
582 if(includeRelationships
.isEmpty()){
586 if(maxDepth
!= null) {
589 if(logger
.isDebugEnabled()){
590 logger
.debug("collecting related taxa for " + taxon
+ " with maxDepth=" + maxDepth
);
592 List
<TaxonRelationship
> taxonRelationships
= dao
.getTaxonRelationships(taxon
, null, null, null, null, null, null);
593 for (TaxonRelationship taxRel
: taxonRelationships
) {
596 if (taxRel
.getToTaxon() == null || taxRel
.getFromTaxon() == null || taxRel
.getType() == null) {
599 // filter by includeRelationships
600 for (TaxonRelationshipEdge relationshipEdgeFilter
: includeRelationships
) {
601 if ( relationshipEdgeFilter
.getTaxonRelationshipType().equals(taxRel
.getType()) ) {
602 if (relationshipEdgeFilter
.getDirections().contains(Direction
.relatedTo
) && !taxa
.contains(taxRel
.getToTaxon())) {
603 if(logger
.isDebugEnabled()){
604 logger
.debug(maxDepth
+ ": " + taxon
.getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxRel
.getToTaxon().getTitleCache());
606 taxa
.add(taxRel
.getToTaxon());
607 if(maxDepth
== null || maxDepth
> 0) {
608 taxa
.addAll(collectRelatedTaxa(taxRel
.getToTaxon(), includeRelationships
, taxa
, maxDepth
));
611 if(relationshipEdgeFilter
.getDirections().contains(Direction
.relatedFrom
) && !taxa
.contains(taxRel
.getFromTaxon())) {
612 taxa
.add(taxRel
.getFromTaxon());
613 if(logger
.isDebugEnabled()){
614 logger
.debug(maxDepth
+ ": " +taxRel
.getFromTaxon().getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxon
.getTitleCache() );
616 if(maxDepth
== null || maxDepth
> 0) {
617 taxa
.addAll(collectRelatedTaxa(taxRel
.getFromTaxon(), includeRelationships
, taxa
, maxDepth
));
627 * @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)
630 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
631 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
633 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
634 if(numberOfResults
> 0) { // no point checking again
635 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
638 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
642 * @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)
645 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
646 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
648 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
649 if(numberOfResults
> 0) { // no point checking again
650 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
653 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
657 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
660 public List
<List
<Synonym
>> getSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
661 List
<List
<Synonym
>> result
= new ArrayList
<List
<Synonym
>>();
662 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
665 result
.add(t
.getHomotypicSynonymsByHomotypicGroup());
668 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
669 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
670 result
.add(t
.getSynonymsInGroup(homotypicalGroup
));
678 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
681 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
682 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
683 return t
.getHomotypicSynonymsByHomotypicGroup();
687 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
690 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
691 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
692 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
693 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
694 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
695 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
697 return heterotypicSynonymyGroups
;
701 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
703 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
704 // Class<? extends TaxonBase> clazz = null;
705 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
706 // clazz = TaxonBase.class;
707 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
708 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
709 // } else if(configurator.isDoTaxa()) {
710 // clazz = Taxon.class;
711 // //propertyPath = configurator.getTaxonPropertyPath();
712 // } else if (configurator.isDoSynonyms()) {
713 // clazz = Synonym.class;
714 // //propertyPath = configurator.getSynonymPropertyPath();
718 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
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 Amplification amplification
= singleRead
.getAmplification();
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
) {
1019 DeleteResult result
= new DeleteResult();
1020 if (config
== null){
1021 config
= new TaxonDeletionConfigurator();
1024 List
<String
> referencedObjects
= isDeletable(taxon
, config
);
1026 if (referencedObjects
.isEmpty()){
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."));
1258 List
<Exception
> exceptions
= new ArrayList
<Exception
>();
1259 for (String message
: referencedObjects
){
1260 ReferencedObjectUndeletableException exception
= new ReferencedObjectUndeletableException(message
);
1261 exceptions
.add(exception
);
1263 result
.addExceptions(exceptions
);
1271 private String
checkForReferences(Taxon taxon
){
1272 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
1273 for (CdmBase referencingObject
: referencingObjects
){
1274 //IIdentificationKeys (Media, Polytomous, MultiAccess)
1275 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
1276 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";
1282 /* //PolytomousKeyNode
1283 if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){
1284 String message = "Taxon" + taxon.getTitleCache() + " can't be deleted as it is used in polytomous key node";
1289 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
1290 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
1295 if (referencingObject
.isInstanceOf(DeterminationEvent
.class)){
1296 String message
= "Taxon can't be deleted as it is used in a determination event";
1302 referencingObjects
= null;
1306 private boolean checkForPolytomousKeys(Taxon taxon
){
1307 boolean result
= false;
1308 List
<CdmBase
> list
= genericDao
.getCdmBasesByFieldAndClass(PolytomousKeyNode
.class, "taxon", taxon
);
1309 if (!list
.isEmpty()) {
1315 @Transactional(readOnly
= false)
1316 public UUID
delete(Synonym syn
){
1317 UUID result
= syn
.getUuid();
1318 this.deleteSynonym(syn
, null);
1325 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1327 @Transactional(readOnly
= false)
1329 public DeleteResult
deleteSynonym(Synonym synonym
, SynonymDeletionConfigurator config
) {
1330 return deleteSynonym(synonym
, null, config
);
1336 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1338 @Transactional(readOnly
= false)
1340 public DeleteResult
deleteSynonym(Synonym synonym
, Taxon taxon
, SynonymDeletionConfigurator config
) {
1341 DeleteResult result
= new DeleteResult();
1342 if (synonym
== null){
1347 if (config
== null){
1348 config
= new SynonymDeletionConfigurator();
1350 List
<String
> messages
= isDeletable(synonym
, config
);
1353 if (messages
.isEmpty()){
1354 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
1356 //remove synonymRelationship
1357 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
1359 taxonSet
.add(taxon
);
1361 taxonSet
.addAll(synonym
.getAcceptedTaxa());
1363 for (Taxon relatedTaxon
: taxonSet
){
1364 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
1365 relatedTaxon
.removeSynonym(synonym
, config
.isNewHomotypicGroupIfNeeded());
1367 this.saveOrUpdate(synonym
);
1369 //TODO remove name from homotypical group?
1371 //remove synonym (if necessary)
1374 if (synonym
.getSynonymRelations().isEmpty()){
1375 TaxonNameBase
<?
,?
> name
= synonym
.getName();
1376 synonym
.setName(null);
1377 uuid
= dao
.delete(synonym
);
1379 //remove name if possible (and required)
1380 if (name
!= null && config
.isDeleteNameIfPossible()){
1382 nameService
.delete(name
, config
.getNameDeletionConfig());
1388 result
.addException(new ReferencedObjectUndeletableException("Synonym can not be deleted it is used in a synonymRelationship."));
1394 List
<Exception
> exceptions
= new ArrayList
<Exception
>();
1395 for (String message
:messages
){
1396 exceptions
.add(new ReferencedObjectUndeletableException(message
));
1399 result
.addExceptions(exceptions
);
1408 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
1411 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
1413 return this.dao
.findIdenticalNamesNew(propertyPath
);
1417 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1420 public String
getPhylumName(TaxonNameBase name
){
1421 return this.dao
.getPhylumName(name
);
1425 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
1428 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
1429 return dao
.deleteSynonymRelationships(syn
, taxon
);
1433 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
1436 public long deleteSynonymRelationships(Synonym syn
) {
1437 return dao
.deleteSynonymRelationships(syn
, null);
1442 * @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)
1445 public List
<SynonymRelationship
> listSynonymRelationships(
1446 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
1447 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
1448 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
1450 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
1451 if(numberOfResults
> 0) { // no point checking again
1452 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
1458 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
1461 public Taxon
findBestMatchingTaxon(String taxonName
) {
1462 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
1463 config
.setTaxonNameTitle(taxonName
);
1464 return findBestMatchingTaxon(config
);
1470 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
1472 Taxon bestCandidate
= null;
1474 // 1. search for acceptet taxa
1475 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1476 boolean bestCandidateMatchesSecUuid
= false;
1477 boolean bestCandidateIsInClassification
= false;
1478 int countEqualCandidates
= 0;
1479 for(TaxonBase taxonBaseCandidate
: taxonList
){
1480 if(taxonBaseCandidate
instanceof Taxon
){
1481 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
1482 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
1483 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
1485 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
1486 bestCandidate
= newCanditate
;
1487 countEqualCandidates
= 1;
1488 bestCandidateMatchesSecUuid
= true;
1492 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
1493 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
1495 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
1496 bestCandidate
= newCanditate
;
1497 countEqualCandidates
= 1;
1498 bestCandidateIsInClassification
= true;
1501 if (bestCandidate
== null){
1502 bestCandidate
= newCanditate
;
1503 countEqualCandidates
= 1;
1507 }else{ //not Taxon.class
1510 countEqualCandidates
++;
1513 if (bestCandidate
!= null){
1514 if(countEqualCandidates
> 1){
1515 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
1516 return bestCandidate
;
1518 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
1519 return bestCandidate
;
1524 // 2. search for synonyms
1525 if (config
.isIncludeSynonyms()){
1526 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1527 for(TaxonBase taxonBase
: synonymList
){
1528 if(taxonBase
instanceof Synonym
){
1529 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
1530 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
1531 if(!acceptetdCandidates
.isEmpty()){
1532 bestCandidate
= acceptetdCandidates
.iterator().next();
1533 if(acceptetdCandidates
.size() == 1){
1534 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
1535 return bestCandidate
;
1537 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
1538 return bestCandidate
;
1540 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
1546 } catch (Exception e
){
1548 e
.printStackTrace();
1551 return bestCandidate
;
1554 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
1555 UUID configClassificationUuid
= config
.getClassificationUuid();
1556 if (configClassificationUuid
== null){
1559 for (TaxonNode node
: taxon
.getTaxonNodes()){
1560 UUID classUuid
= node
.getClassification().getUuid();
1561 if (configClassificationUuid
.equals(classUuid
)){
1568 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1569 UUID configSecUuid
= config
.getSecUuid();
1570 if (configSecUuid
== null){
1573 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1574 return configSecUuid
.equals(taxonSecUuid
);
1578 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1581 public Synonym
findBestMatchingSynonym(String taxonName
) {
1582 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1583 if(! synonymList
.isEmpty()){
1584 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1585 if(synonymList
.size() == 1){
1586 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1589 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1598 * @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)
1601 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1602 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1604 Synonym synonym
= oldSynonymRelation
.getSynonym();
1605 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1606 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1607 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1608 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1609 //set default relationship type
1610 if (newSynonymRelationshipType
== null){
1611 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1613 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1615 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1616 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1617 boolean isSingleInGroup
= !(hgSize
> 1);
1619 if (! isSingleInGroup
){
1620 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1621 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1622 if (isHomotypicToAccepted
){
1623 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.";
1624 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1625 message
= String
.format(message
, homotypicRelatives
);
1626 throw new HomotypicalGroupChangeException(message
);
1628 if (! moveHomotypicGroup
){
1629 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.";
1630 throw new HomotypicalGroupChangeException(message
);
1633 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1635 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1637 SynonymRelationship result
= null;
1638 //move all synonyms to new taxon
1639 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1640 for (Synonym syn
: homotypicSynonyms
){
1641 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1642 for (SynonymRelationship synRelation
: synRelations
){
1643 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1644 Reference
<?
> newReference
= reference
;
1645 if (newReference
== null && keepReference
){
1646 newReference
= synRelation
.getCitation();
1648 String newRefDetail
= referenceDetail
;
1649 if (newRefDetail
== null && keepReference
){
1650 newRefDetail
= synRelation
.getCitationMicroReference();
1652 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1653 fromTaxon
.removeSynonymRelation(synRelation
, false);
1655 //change homotypic group of synonym if relType is 'homotypic'
1656 // if (newRelTypeIsHomotypic){
1657 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1660 if (synRelation
.equals(oldSynonymRelation
)){
1661 result
= newSynRelation
;
1667 saveOrUpdate(newTaxon
);
1668 //Assert that there is a result
1669 if (result
== null){
1670 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1671 throw new IllegalStateException(message
);
1677 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1680 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1681 return dao
.getUuidAndTitleCacheTaxon();
1685 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1688 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1689 return dao
.getUuidAndTitleCacheSynonym();
1693 * @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)
1696 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1697 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1698 Classification classification
, List
<Language
> languages
,
1699 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1702 LuceneSearch luceneSearch
= prepareFindByFullTextSearch(clazz
, queryString
, classification
, languages
, highlightFragments
, null);
1704 // --- execute search
1705 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1707 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1708 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1710 // --- initialize taxa, thighlight matches ....
1711 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1712 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1713 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1715 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1716 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1720 public Pager
<SearchResult
<TaxonBase
>> findByDistribution(List
<NamedArea
> areaFilter
, List
<PresenceAbsenceTermBase
<?
>> statusFilter
,
1721 Classification classification
,
1722 Integer pageSize
, Integer pageNumber
,
1723 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws IOException
, ParseException
{
1725 LuceneSearch luceneSearch
= prepareByDistributionSearch(areaFilter
, statusFilter
, classification
);
1727 // --- execute search
1728 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1730 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1731 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1733 // --- initialize taxa, thighlight matches ....
1734 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1735 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1736 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1738 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1739 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1744 * @param queryString
1745 * @param classification
1747 * @param highlightFragments
1748 * @param sortFields TODO
1749 * @param directorySelectClass
1752 protected LuceneSearch
prepareFindByFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Language
> languages
,
1753 boolean highlightFragments
, SortField
[] sortFields
) {
1754 BooleanQuery finalQuery
= new BooleanQuery();
1755 BooleanQuery textQuery
= new BooleanQuery();
1757 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, TaxonBase
.class);
1758 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1760 if(sortFields
== null){
1761 sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1763 luceneSearch
.setSortFields(sortFields
);
1765 // ---- search criteria
1766 luceneSearch
.setCdmTypRestriction(clazz
);
1768 textQuery
.add(taxonBaseQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1769 textQuery
.add(taxonBaseQueryFactory
.newDefinedTermQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1771 finalQuery
.add(textQuery
, Occur
.MUST
);
1773 if(classification
!= null){
1774 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1776 luceneSearch
.setQuery(finalQuery
);
1778 if(highlightFragments
){
1779 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1781 return luceneSearch
;
1785 * Uses org.apache.lucene.search.join.JoinUtil for query time joining, alternatively
1786 * the BlockJoinQuery could be used. The latter might be more memory save but has the
1787 * drawback of requiring to do the join an indexing time.
1788 * see http://dev.e-taxonomy.eu/trac/wiki/LuceneNotes#JoinsinLucene for more information on this.
1790 * Joins TaxonRelationShip with Taxon depending on the direction of the given edge:
1792 * <li>direct, everted: {@link Direction.relatedTo}: TaxonRelationShip.relatedTo.id --> Taxon.id </li>
1793 * <li>inverse: {@link Direction.relatedFrom}: TaxonRelationShip.relatedFrom.id --> Taxon.id </li>
1795 * @param queryString
1796 * @param classification
1798 * @param highlightFragments
1799 * @param sortFields TODO
1802 * @throws IOException
1804 protected LuceneSearch
prepareFindByTaxonRelationFullTextSearch(TaxonRelationshipEdge edge
, String queryString
, Classification classification
, List
<Language
> languages
,
1805 boolean highlightFragments
, SortField
[] sortFields
) throws IOException
{
1808 String queryTermField
;
1809 String toField
= "id"; // TaxonBase.uuid
1811 if(edge
.isBidirectional()){
1812 throw new RuntimeException("Bidirectional joining not supported!");
1815 fromField
= "relatedFrom.id";
1816 queryTermField
= "relatedFrom.titleCache";
1817 } else if(edge
.isInvers()) {
1818 fromField
= "relatedTo.id";
1819 queryTermField
= "relatedTo.titleCache";
1821 throw new RuntimeException("Invalid direction: " + edge
.getDirections());
1824 BooleanQuery finalQuery
= new BooleanQuery();
1826 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, TaxonBase
.class);
1827 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1829 BooleanQuery joinFromQuery
= new BooleanQuery();
1830 joinFromQuery
.add(taxonBaseQueryFactory
.newTermQuery(queryTermField
, queryString
), Occur
.MUST
);
1831 joinFromQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("type.id", edge
.getTaxonRelationshipType()), Occur
.MUST
);
1832 Query joinQuery
= taxonBaseQueryFactory
.newJoinQuery(fromField
, toField
, joinFromQuery
, TaxonRelationship
.class);
1834 if(sortFields
== null){
1835 sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1837 luceneSearch
.setSortFields(sortFields
);
1839 finalQuery
.add(joinQuery
, Occur
.MUST
);
1841 if(classification
!= null){
1842 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1844 luceneSearch
.setQuery(finalQuery
);
1846 if(highlightFragments
){
1847 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1849 return luceneSearch
;
1856 * @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)
1859 public Pager
<SearchResult
<TaxonBase
>> findTaxaAndNamesByFullText(
1860 EnumSet
<TaxaAndNamesSearchMode
> searchModes
, String queryString
, Classification classification
,
1861 Set
<NamedArea
> namedAreas
, Set
<PresenceAbsenceTermBase
<?
>> distributionStatus
, List
<Language
> languages
,
1862 boolean highlightFragments
, Integer pageSize
,
1863 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
)
1864 throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
1866 // FIXME: allow taxonomic ordering
1867 // 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";
1868 // this require building a special sort column by a special classBridge
1869 if(highlightFragments
){
1870 logger
.warn("findTaxaAndNamesByFullText() : fragment highlighting is " +
1871 "currently not fully supported by this method and thus " +
1872 "may not work with common names and misapplied names.");
1875 // convert sets to lists
1876 List
<NamedArea
> namedAreaList
= null;
1877 List
<PresenceAbsenceTermBase
<?
>>distributionStatusList
= null;
1878 if(namedAreas
!= null){
1879 namedAreaList
= new ArrayList
<NamedArea
>(namedAreas
.size());
1880 namedAreaList
.addAll(namedAreas
);
1882 if(distributionStatus
!= null){
1883 distributionStatusList
= new ArrayList
<PresenceAbsenceTermBase
<?
>>(distributionStatus
.size());
1884 distributionStatusList
.addAll(distributionStatus
);
1887 // set default if parameter is null
1888 if(searchModes
== null){
1889 searchModes
= EnumSet
.of(TaxaAndNamesSearchMode
.doTaxa
);
1892 // set sort order and thus override any sort orders which may have been
1893 // defindes by prepare*Search methods
1894 if(orderHints
== null){
1895 orderHints
= OrderHint
.NOMENCLATURAL_SORT_ORDER
;
1897 SortField
[] sortFields
= new SortField
[orderHints
.size()];
1899 for(OrderHint oh
: orderHints
){
1900 sortFields
[i
++] = oh
.toSortField();
1902 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("id", SortField.STRING, false)};
1903 // SortField[] sortFields = new SortField[]{new SortField(NomenclaturalSortOrderBrigde.NAME_SORT_FIELD_NAME, SortField.STRING, false)};
1906 boolean addDistributionFilter
= namedAreas
!= null && namedAreas
.size() > 0;
1908 List
<LuceneSearch
> luceneSearches
= new ArrayList
<LuceneSearch
>();
1909 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1912 ======== filtering by distribution , HOWTO ========
1914 - http://www.javaranch.com/journal/2009/02/filtering-a-lucene-search.html
1915 - http://stackoverflow.com/questions/17709256/lucene-solr-using-complex-filters -> QueryWrapperFilter
1916 add Filter to search as http://lucene.apache.org/core/3_6_0/api/all/org/apache/lucene/search/Filter.html
1917 which will be put into a FilteredQuersy in the end ?
1920 3. how does it work in spatial?
1922 - http://www.nsshutdown.com/projects/lucene/whitepaper/locallucene_v2.html
1923 - http://www.infoq.com/articles/LuceneSpatialSupport
1924 - http://www.mhaller.de/archives/156-Spatial-search-with-Lucene.html
1925 ------------------------------------------------------------------------
1928 A) use a separate distribution filter per index sub-query/search:
1929 - byTaxonSyonym (query TaxaonBase):
1930 use a join area filter (Distribution -> TaxonBase)
1931 - byCommonName (query DescriptionElementBase): use an area filter on
1932 DescriptionElementBase !!! PROBLEM !!!
1933 This cannot work since the distributions are different entities than the
1934 common names and thus these are different lucene documents.
1935 - byMisaplliedNames (join query TaxonRelationship -> TaxaonBase):
1936 use a join area filter (Distribution -> TaxonBase)
1938 B) use a common distribution filter for all index sub-query/searches:
1939 - use a common join area filter (Distribution -> TaxonBase)
1940 - also implement the byCommonName as join query (CommonName -> TaxonBase)
1941 PROBLEM in this case: we are losing the fragment highlighting for the
1942 common names, since the returned documents are always TaxonBases
1945 /* The QueryFactory for creating filter queries on Distributions should
1946 * The query factory used for the common names query cannot be reused
1947 * for this case, since we want to only record the text fields which are
1948 * actually used in the primary query
1950 QueryFactory distributionFilterQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Distribution
.class);
1952 BooleanFilter multiIndexByAreaFilter
= new BooleanFilter();
1955 // search for taxa or synonyms
1956 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) || searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1957 Class taxonBaseSubclass
= TaxonBase
.class;
1958 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && !searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1959 taxonBaseSubclass
= Taxon
.class;
1960 } else if (!searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1961 taxonBaseSubclass
= Synonym
.class;
1963 luceneSearches
.add(prepareFindByFullTextSearch(taxonBaseSubclass
, queryString
, classification
, languages
, highlightFragments
, sortFields
));
1964 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1965 /* A) does not work!!!!
1966 if(addDistributionFilter){
1967 // in this case we need a filter which uses a join query
1968 // to get the TaxonBase documents for the DescriptionElementBase documents
1969 // which are matching the areas in question
1970 Query taxonAreaJoinQuery = createByDistributionJoinQuery(
1972 distributionStatusList,
1973 distributionFilterQueryFactory
1975 multiIndexByAreaFilter.add(new QueryWrapperFilter(taxonAreaJoinQuery), Occur.SHOULD);
1978 if(addDistributionFilter
&& searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1979 // add additional area filter for synonyms
1980 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
1981 String toField
= "accTaxon.id"; // id in TaxonBase index
1983 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, distributionFilterQueryFactory
);
1985 Query taxonAreaJoinQuery
= distributionFilterQueryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
1986 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
1991 // search by CommonTaxonName
1992 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxaByCommonNames
)) {
1994 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
1995 Query byCommonNameJoinQuery
= descriptionElementQueryFactory
.newJoinQuery(
1996 "inDescription.taxon.id",
1998 QueryFactory
.addTypeRestriction(
1999 createByDescriptionElementFullTextQuery(queryString
, classification
, null, languages
, descriptionElementQueryFactory
)
2000 , CommonTaxonName
.class
2002 CommonTaxonName
.class);
2003 logger
.debug("byCommonNameJoinQuery: " + byCommonNameJoinQuery
.toString());
2004 LuceneSearch byCommonNameSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
2005 byCommonNameSearch
.setCdmTypRestriction(Taxon
.class);
2006 byCommonNameSearch
.setQuery(byCommonNameJoinQuery
);
2007 byCommonNameSearch
.setSortFields(sortFields
);
2008 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
2010 luceneSearches
.add(byCommonNameSearch
);
2012 /* A) does not work!!!!
2014 prepareByDescriptionElementFullTextSearch(CommonTaxonName.class,
2015 queryString, classification, null, languages, highlightFragments)
2017 idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id");
2018 if(addDistributionFilter){
2019 // in this case we are able to use DescriptionElementBase documents
2020 // which are matching the areas in question directly
2021 BooleanQuery byDistributionQuery = createByDistributionQuery(
2023 distributionStatusList,
2024 distributionFilterQueryFactory
2026 multiIndexByAreaFilter.add(new QueryWrapperFilter(byDistributionQuery), Occur.SHOULD);
2030 // search by misapplied names
2031 if(searchModes
.contains(TaxaAndNamesSearchMode
.doMisappliedNames
)) {
2033 // prepareFindByTaxonRelationFullTextSearch() is making use of JoinUtil.createJoinQuery()
2034 // which allows doing query time joins
2035 // finds the misapplied name (Taxon B) which is an misapplication for
2036 // a related Taxon A.
2038 luceneSearches
.add(prepareFindByTaxonRelationFullTextSearch(
2039 new TaxonRelationshipEdge(TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), Direction
.relatedTo
),
2040 queryString
, classification
, languages
, highlightFragments
, sortFields
));
2041 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
2043 if(addDistributionFilter
){
2044 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
2047 * Here i was facing wired and nasty bug which took me bugging be really for hours until I found this solution.
2048 * Maybe this is a but in java itself java.
2050 * When the string toField is constructed by using the expression TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString()
2053 * String toField = "relation." + TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString() +".to.id";
2055 * The byDistributionQuery fails, however when the uuid is first stored in another string variable the query
2056 * will execute as expected:
2058 * String misappliedNameForUuid = TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString();
2059 * String toField = "relation." + misappliedNameForUuid +".to.id";
2061 * Comparing both strings by the String.equals method returns true, so both String are identical.
2063 * The bug occurs when running eu.etaxonomy.cdm.api.service.TaxonServiceSearchTest in eclipse and in maven and seems to to be
2064 * 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)
2065 * The bug is persistent after a reboot of the development computer.
2067 // String misappliedNameForUuid = TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString();
2068 // String toField = "relation." + misappliedNameForUuid +".to.id";
2069 String toField
= "relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id";
2070 // System.out.println("relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id".equals("relation." + misappliedNameForUuid +".to.id") ? " > identical" : " > different");
2071 // System.out.println("relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id".equals("relation." + TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString() +".to.id") ? " > identical" : " > different");
2073 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, distributionFilterQueryFactory
);
2074 Query taxonAreaJoinQuery
= distributionFilterQueryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
2075 QueryWrapperFilter filter
= new QueryWrapperFilter(taxonAreaJoinQuery
);
2077 // debug code for bug described above
2078 DocIdSet filterMatchSet
= filter
.getDocIdSet(luceneIndexToolProvider
.getIndexReaderFor(Taxon
.class));
2079 // System.err.println(DocIdBitSetPrinter.docsAsString(filterMatchSet, 100));
2081 multiIndexByAreaFilter
.add(filter
, Occur
.SHOULD
);
2085 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
,
2086 luceneSearches
.toArray(new LuceneSearch
[luceneSearches
.size()]));
2089 if(addDistributionFilter
){
2092 // in this case we need a filter which uses a join query
2093 // to get the TaxonBase documents for the DescriptionElementBase documents
2094 // which are matching the areas in question
2096 // for toTaxa, doByCommonName
2097 Query taxonAreaJoinQuery
= createByDistributionJoinQuery(
2099 distributionStatusList
,
2100 distributionFilterQueryFactory
2102 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
2105 if (addDistributionFilter
){
2106 multiSearch
.setFilter(multiIndexByAreaFilter
);
2110 // --- execute search
2111 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
2113 // --- initialize taxa, highlight matches ....
2114 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
2117 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
2118 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
2120 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
2121 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
2125 * @param namedAreaList at least one area must be in the list
2126 * @param distributionStatusList optional
2128 * @throws IOException
2130 protected Query
createByDistributionJoinQuery(
2131 List
<NamedArea
> namedAreaList
,
2132 List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
,
2133 QueryFactory queryFactory
2134 ) throws IOException
{
2136 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
2137 String toField
= "id"; // id in TaxonBase index
2139 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, queryFactory
);
2141 Query taxonAreaJoinQuery
= queryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
2143 return taxonAreaJoinQuery
;
2147 * @param namedAreaList
2148 * @param distributionStatusList
2149 * @param queryFactory
2152 private BooleanQuery
createByDistributionQuery(List
<NamedArea
> namedAreaList
,
2153 List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
, QueryFactory queryFactory
) {
2154 BooleanQuery areaQuery
= new BooleanQuery();
2155 // area field from Distribution
2156 areaQuery
.add(queryFactory
.newEntityIdsQuery("area.id", namedAreaList
), Occur
.MUST
);
2158 // status field from Distribution
2159 if(distributionStatusList
!= null && distributionStatusList
.size() > 0){
2160 areaQuery
.add(queryFactory
.newEntityIdsQuery("status.id", distributionStatusList
), Occur
.MUST
);
2163 logger
.debug("createByDistributionQuery() query: " + areaQuery
.toString());
2168 * This method has been primarily created for testing the area join query but might
2169 * also be useful in other situations
2171 * @param namedAreaList
2172 * @param distributionStatusList
2173 * @param classification
2174 * @param highlightFragments
2176 * @throws IOException
2178 protected LuceneSearch
prepareByDistributionSearch(
2179 List
<NamedArea
> namedAreaList
, List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
,
2180 Classification classification
) throws IOException
{
2182 BooleanQuery finalQuery
= new BooleanQuery();
2184 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
2186 // FIXME is this query factory using the wrong type?
2187 QueryFactory taxonQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Taxon
.class);
2189 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
2190 luceneSearch
.setSortFields(sortFields
);
2193 Query byAreaQuery
= createByDistributionJoinQuery(namedAreaList
, distributionStatusList
, taxonQueryFactory
);
2195 finalQuery
.add(byAreaQuery
, Occur
.MUST
);
2197 if(classification
!= null){
2198 finalQuery
.add(taxonQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
2201 logger
.info("prepareByAreaSearch() query: " + finalQuery
.toString());
2202 luceneSearch
.setQuery(finalQuery
);
2204 return luceneSearch
;
2210 * @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)
2213 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
2214 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
2215 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
2216 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
2219 LuceneSearch luceneSearch
= prepareByDescriptionElementFullTextSearch(clazz
, queryString
, classification
, features
, languages
, highlightFragments
);
2221 // --- execute search
2222 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
2224 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
2225 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
2227 // --- initialize taxa, highlight matches ....
2228 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
2229 @SuppressWarnings("rawtypes")
2230 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
2231 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
2233 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
2234 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
2240 public Pager
<SearchResult
<TaxonBase
>> findByEverythingFullText(String queryString
,
2241 Classification classification
, List
<Language
> languages
, boolean highlightFragments
,
2242 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
2244 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, null, languages
, highlightFragments
);
2245 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
, null);
2247 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
, luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
2249 // --- execute search
2250 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
2252 // --- initialize taxa, highlight matches ....
2253 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
2255 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
2256 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
2257 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
2259 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
2260 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
2262 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
2263 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
2270 * @param queryString
2271 * @param classification
2274 * @param highlightFragments
2275 * @param directorySelectClass
2278 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
,
2279 String queryString
, Classification classification
, List
<Feature
> features
,
2280 List
<Language
> languages
, boolean highlightFragments
) {
2282 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, DescriptionElementBase
.class);
2283 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
2285 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", SortField
.STRING
, false)};
2287 BooleanQuery finalQuery
= createByDescriptionElementFullTextQuery(queryString
, classification
, features
,
2288 languages
, descriptionElementQueryFactory
);
2290 luceneSearch
.setSortFields(sortFields
);
2291 luceneSearch
.setCdmTypRestriction(clazz
);
2292 luceneSearch
.setQuery(finalQuery
);
2293 if(highlightFragments
){
2294 luceneSearch
.setHighlightFields(descriptionElementQueryFactory
.getTextFieldNamesAsArray());
2297 return luceneSearch
;
2301 * @param queryString
2302 * @param classification
2305 * @param descriptionElementQueryFactory
2308 private BooleanQuery
createByDescriptionElementFullTextQuery(String queryString
, Classification classification
,
2309 List
<Feature
> features
, List
<Language
> languages
, QueryFactory descriptionElementQueryFactory
) {
2310 BooleanQuery finalQuery
= new BooleanQuery();
2311 BooleanQuery textQuery
= new BooleanQuery();
2312 textQuery
.add(descriptionElementQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
2316 if(languages
== null || languages
.size() == 0){
2317 nameQuery
= descriptionElementQueryFactory
.newTermQuery("name", queryString
);
2319 nameQuery
= new BooleanQuery();
2320 BooleanQuery languageSubQuery
= new BooleanQuery();
2321 for(Language lang
: languages
){
2322 languageSubQuery
.add(descriptionElementQueryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString(), false), Occur
.SHOULD
);
2324 ((BooleanQuery
) nameQuery
).add(descriptionElementQueryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
2325 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
2327 textQuery
.add(nameQuery
, Occur
.SHOULD
);
2330 // text field from TextData
2331 textQuery
.add(descriptionElementQueryFactory
.newMultilanguageTextQuery("text", queryString
, languages
), Occur
.SHOULD
);
2333 // --- TermBase fields - by representation ----
2334 // state field from CategoricalData
2335 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("stateData.state", queryString
, languages
), Occur
.SHOULD
);
2337 // state field from CategoricalData
2338 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("stateData.modifyingText", queryString
, languages
), Occur
.SHOULD
);
2340 // area field from Distribution
2341 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("area", queryString
, languages
), Occur
.SHOULD
);
2343 // status field from Distribution
2344 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("status", queryString
, languages
), Occur
.SHOULD
);
2346 finalQuery
.add(textQuery
, Occur
.MUST
);
2347 // --- classification ----
2349 if(classification
!= null){
2350 finalQuery
.add(descriptionElementQueryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
2353 // --- IdentifieableEntity fields - by uuid
2354 if(features
!= null && features
.size() > 0 ){
2355 finalQuery
.add(descriptionElementQueryFactory
.newEntityUuidsQuery("feature.uuid", features
), Occur
.MUST
);
2358 // the description must be associated with a taxon
2359 finalQuery
.add(descriptionElementQueryFactory
.newIsNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
2361 logger
.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery
.toString());
2366 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
2367 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
2368 * This method is a convenient means to retrieve a Lucene query string for such the fields.
2370 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
2371 * or {@link MultilanguageTextFieldBridge }
2372 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
2373 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
2374 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
2376 * TODO move to utiliy class !!!!!!!!
2378 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
2380 if(stringBuilder
== null){
2381 stringBuilder
= new StringBuilder();
2383 if(languages
== null || languages
.size() == 0){
2384 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
2386 for(Language lang
: languages
){
2387 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
2390 return stringBuilder
;
2394 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
2395 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2396 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
2398 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
2401 UUID nameUuid
= taxon
.getName().getUuid();
2402 ZoologicalName taxonName
= getZoologicalName(nameUuid
, zooHashMap
);
2403 String epithetOfTaxon
= null;
2404 String infragenericEpithetOfTaxon
= null;
2405 String infraspecificEpithetOfTaxon
= null;
2406 if (taxonName
.isSpecies()){
2407 epithetOfTaxon
= taxonName
.getSpecificEpithet();
2408 } else if (taxonName
.isInfraGeneric()){
2409 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
2410 } else if (taxonName
.isInfraSpecific()){
2411 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
2413 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
2414 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
2415 List
<String
> taxonNames
= new ArrayList
<String
>();
2417 for (TaxonNode node
: nodes
){
2418 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
2419 // List<String> synonymsEpithet = new ArrayList<String>();
2421 if (node
.getClassification().equals(classification
)){
2422 if (!node
.isTopmostNode()){
2423 TaxonNode parent
= node
.getParent();
2424 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
2425 TaxonNameBase
<?
,?
> parentName
= parent
.getTaxon().getName();
2426 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
2427 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
2428 Rank rankOfTaxon
= taxonName
.getRank();
2431 //create inferred synonyms for species, subspecies
2432 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
2434 Synonym inferredEpithet
= null;
2435 Synonym inferredGenus
= null;
2436 Synonym potentialCombination
= null;
2438 List
<String
> propertyPaths
= new ArrayList
<String
>();
2439 propertyPaths
.add("synonym");
2440 propertyPaths
.add("synonym.name");
2441 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
2442 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
2444 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2445 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2447 List
<TaxonRelationship
> taxonRelListParent
= null;
2448 List
<TaxonRelationship
> taxonRelListTaxon
= null;
2449 if (doWithMisappliedNames
){
2450 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2451 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2455 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
2458 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2459 Synonym syn
= synonymRelationOfParent
.getSynonym();
2461 inferredEpithet
= createInferredEpithets(taxon
,
2462 zooHashMap
, taxonName
, epithetOfTaxon
,
2463 infragenericEpithetOfTaxon
,
2464 infraspecificEpithetOfTaxon
,
2465 taxonNames
, parentName
,
2469 inferredSynonyms
.add(inferredEpithet
);
2470 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2471 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2474 if (doWithMisappliedNames
){
2476 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
2477 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2479 inferredEpithet
= createInferredEpithets(taxon
,
2480 zooHashMap
, taxonName
, epithetOfTaxon
,
2481 infragenericEpithetOfTaxon
,
2482 infraspecificEpithetOfTaxon
,
2483 taxonNames
, parentName
,
2486 inferredSynonyms
.add(inferredEpithet
);
2487 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2488 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2492 if (!taxonNames
.isEmpty()){
2493 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2494 ZoologicalName name
;
2495 if (!synNotInCDM
.isEmpty()){
2496 inferredSynonymsToBeRemoved
.clear();
2498 for (Synonym syn
:inferredSynonyms
){
2499 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2500 if (!synNotInCDM
.contains(name
.getNameCache())){
2501 inferredSynonymsToBeRemoved
.add(syn
);
2505 // Remove identified Synonyms from inferredSynonyms
2506 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2507 inferredSynonyms
.remove(synonym
);
2512 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
2515 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2516 TaxonNameBase synName
;
2517 ZoologicalName inferredSynName
;
2519 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2520 inferredGenus
= createInferredGenus(taxon
,
2521 zooHashMap
, taxonName
, epithetOfTaxon
,
2522 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
2524 inferredSynonyms
.add(inferredGenus
);
2525 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2526 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2531 if (doWithMisappliedNames
){
2533 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2534 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2535 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
2537 inferredSynonyms
.add(inferredGenus
);
2538 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2539 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2544 if (!taxonNames
.isEmpty()){
2545 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2546 ZoologicalName name
;
2547 if (!synNotInCDM
.isEmpty()){
2548 inferredSynonymsToBeRemoved
.clear();
2550 for (Synonym syn
:inferredSynonyms
){
2551 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2552 if (!synNotInCDM
.contains(name
.getNameCache())){
2553 inferredSynonymsToBeRemoved
.add(syn
);
2557 // Remove identified Synonyms from inferredSynonyms
2558 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2559 inferredSynonyms
.remove(synonym
);
2564 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
2566 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
2567 ZoologicalName inferredSynName
;
2568 //for all synonyms of the parent...
2569 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2570 TaxonNameBase synName
;
2571 Synonym synParent
= synonymRelationOfParent
.getSynonym();
2572 synName
= synParent
.getName();
2574 HibernateProxyHelper
.deproxy(synParent
);
2576 // Set the sourceReference
2577 sourceReference
= synParent
.getSec();
2579 // Determine the idInSource
2580 String idInSourceParent
= getIdInSource(synParent
);
2582 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2583 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2584 String synParentInfragenericName
= null;
2585 String synParentSpecificEpithet
= null;
2587 if (parentSynZooName
.isInfraGeneric()){
2588 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2590 if (parentSynZooName
.isSpecies()){
2591 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2594 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2595 synonymsGenus.put(synGenusName, idInSource);
2598 //for all synonyms of the taxon
2600 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2602 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2603 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2604 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
2606 synParentInfragenericName
,
2607 synParentSpecificEpithet
, syn
, zooHashMap
);
2609 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2610 inferredSynonyms
.add(potentialCombination
);
2611 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2612 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2619 if (doWithMisappliedNames
){
2621 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
2623 TaxonNameBase misappliedParentName
;
2625 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
2626 misappliedParentName
= misappliedParent
.getName();
2628 HibernateProxyHelper
.deproxy(misappliedParent
);
2630 // Set the sourceReference
2631 sourceReference
= misappliedParent
.getSec();
2633 // Determine the idInSource
2634 String idInSourceParent
= getIdInSource(misappliedParent
);
2636 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
2637 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2638 String synParentInfragenericName
= null;
2639 String synParentSpecificEpithet
= null;
2641 if (parentSynZooName
.isInfraGeneric()){
2642 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2644 if (parentSynZooName
.isSpecies()){
2645 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2649 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2650 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2651 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
2652 potentialCombination
= createPotentialCombination(
2653 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
2655 synParentInfragenericName
,
2656 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
2659 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2660 inferredSynonyms
.add(potentialCombination
);
2661 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2662 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2667 if (!taxonNames
.isEmpty()){
2668 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2669 ZoologicalName name
;
2670 if (!synNotInCDM
.isEmpty()){
2671 inferredSynonymsToBeRemoved
.clear();
2672 for (Synonym syn
:inferredSynonyms
){
2674 name
= (ZoologicalName
) syn
.getName();
2675 }catch (ClassCastException e
){
2676 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2678 if (!synNotInCDM
.contains(name
.getNameCache())){
2679 inferredSynonymsToBeRemoved
.add(syn
);
2682 // Remove identified Synonyms from inferredSynonyms
2683 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2684 inferredSynonyms
.remove(synonym
);
2690 logger
.info("The synonymrelationship type is not defined.");
2691 return inferredSynonyms
;
2698 return inferredSynonyms
;
2701 private Synonym
createPotentialCombination(String idInSourceParent
,
2702 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
2703 String synParentInfragenericName
, String synParentSpecificEpithet
,
2704 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2705 Synonym potentialCombination
;
2706 Reference sourceReference
;
2707 ZoologicalName inferredSynName
;
2708 HibernateProxyHelper
.deproxy(syn
);
2710 // Set sourceReference
2711 sourceReference
= syn
.getSec();
2712 if (sourceReference
== null){
2713 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2715 if (!parentSynZooName
.getTaxa().isEmpty()){
2716 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
2718 sourceReference
= taxon
.getSec();
2721 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
2723 String synTaxonInfraSpecificName
= null;
2725 if (parentSynZooName
.isSpecies()){
2726 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
2729 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
2730 synonymsEpithet.add(epithetName);
2733 //create potential combinations...
2734 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
2736 inferredSynName
.setGenusOrUninomial(synParentGenus
);
2737 if (zooSynName
.isSpecies()){
2738 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
2739 if (parentSynZooName
.isInfraGeneric()){
2740 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2743 if (zooSynName
.isInfraSpecific()){
2744 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
2745 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
2747 if (parentSynZooName
.isInfraGeneric()){
2748 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2752 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
2754 // Set the sourceReference
2755 potentialCombination
.setSec(sourceReference
);
2758 // Determine the idInSource
2759 String idInSourceSyn
= getIdInSource(syn
);
2761 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
2762 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
, idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2763 inferredSynName
.addSource(originalSource
);
2764 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
, idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2765 potentialCombination
.addSource(originalSource
);
2768 return potentialCombination
;
2771 private Synonym
createInferredGenus(Taxon taxon
,
2772 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2773 String epithetOfTaxon
, String genusOfTaxon
,
2774 List
<String
> taxonNames
, ZoologicalName zooParentName
,
2777 Synonym inferredGenus
;
2778 TaxonNameBase synName
;
2779 ZoologicalName inferredSynName
;
2780 synName
=syn
.getName();
2781 HibernateProxyHelper
.deproxy(syn
);
2783 // Determine the idInSource
2784 String idInSourceSyn
= getIdInSource(syn
);
2785 String idInSourceTaxon
= getIdInSource(taxon
);
2786 // Determine the sourceReference
2787 Reference sourceReference
= syn
.getSec();
2789 //logger.warn(sourceReference.getTitleCache());
2791 synName
= syn
.getName();
2792 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2793 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
2794 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
2795 synonymsEpithet.add(synSpeciesEpithetName);
2798 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2799 //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...
2802 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
2803 if (zooParentName
.isInfraGeneric()){
2804 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
2807 if (taxonName
.isSpecies()){
2808 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
2810 if (taxonName
.isInfraSpecific()){
2811 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2812 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
2816 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
2818 // Set the sourceReference
2819 inferredGenus
.setSec(sourceReference
);
2821 // Add the original source
2822 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
2823 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2824 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2825 inferredGenus
.addSource(originalSource
);
2827 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2828 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2829 inferredSynName
.addSource(originalSource
);
2830 originalSource
= null;
2833 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
2834 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2835 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2836 inferredGenus
.addSource(originalSource
);
2838 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2839 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2840 inferredSynName
.addSource(originalSource
);
2841 originalSource
= null;
2844 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
2846 return inferredGenus
;
2849 private Synonym
createInferredEpithets(Taxon taxon
,
2850 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2851 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
2852 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
2853 TaxonNameBase parentName
, TaxonBase syn
) {
2855 Synonym inferredEpithet
;
2856 TaxonNameBase
<?
,?
> synName
;
2857 ZoologicalName inferredSynName
;
2858 HibernateProxyHelper
.deproxy(syn
);
2860 // Determine the idInSource
2861 String idInSourceSyn
= getIdInSource(syn
);
2862 String idInSourceTaxon
= getIdInSource(taxon
);
2863 // Determine the sourceReference
2864 Reference
<?
> sourceReference
= syn
.getSec();
2866 if (sourceReference
== null){
2867 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
2868 sourceReference
= taxon
.getSec();
2871 synName
= syn
.getName();
2872 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2873 String synGenusName
= zooSynName
.getGenusOrUninomial();
2874 String synInfraGenericEpithet
= null;
2875 String synSpecificEpithet
= null;
2877 if (zooSynName
.getInfraGenericEpithet() != null){
2878 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
2881 if (zooSynName
.isInfraSpecific()){
2882 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
2885 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2886 synonymsGenus.put(synGenusName, idInSource);
2889 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2891 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
2892 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
2893 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
2895 inferredSynName
.setGenusOrUninomial(synGenusName
);
2897 if (parentName
.isInfraGeneric()){
2898 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
2900 if (taxonName
.isSpecies()){
2901 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2902 }else if (taxonName
.isInfraSpecific()){
2903 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
2904 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
2907 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
2909 // Set the sourceReference
2910 inferredEpithet
.setSec(sourceReference
);
2912 /* Add the original source
2913 if (idInSource != null) {
2914 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
2917 Reference citation = getCitation(syn);
2918 if (citation != null) {
2919 originalSource.setCitation(citation);
2920 inferredEpithet.addSource(originalSource);
2923 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
2926 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2927 taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2929 inferredEpithet
.addSource(originalSource
);
2931 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2932 taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2934 inferredSynName
.addSource(originalSource
);
2938 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
2940 return inferredEpithet
;
2944 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
2945 * Very likely only useful for createInferredSynonyms().
2950 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2951 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
2952 if (taxonName
== null) {
2953 taxonName
= zooHashMap
.get(uuid
);
2959 * Returns the idInSource for a given Synonym.
2962 private String
getIdInSource(TaxonBase taxonBase
) {
2963 String idInSource
= null;
2964 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
2965 if (sources
.size() == 1) {
2966 IdentifiableSource source
= sources
.iterator().next();
2967 if (source
!= null) {
2968 idInSource
= source
.getIdInSource();
2970 } else if (sources
.size() > 1) {
2973 for (IdentifiableSource source
: sources
) {
2974 idInSource
+= source
.getIdInSource();
2975 if (count
< sources
.size()) {
2980 } else if (sources
.size() == 0){
2981 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
2990 * Returns the citation for a given Synonym.
2993 private Reference
getCitation(Synonym syn
) {
2994 Reference citation
= null;
2995 Set
<IdentifiableSource
> sources
= syn
.getSources();
2996 if (sources
.size() == 1) {
2997 IdentifiableSource source
= sources
.iterator().next();
2998 if (source
!= null) {
2999 citation
= source
.getCitation();
3001 } else if (sources
.size() > 1) {
3002 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
3009 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
3010 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
3012 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
3013 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
3014 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
3016 return inferredSynonyms
;
3020 public List
<Classification
> listClassifications(TaxonBase taxonBase
, Integer limit
, Integer start
, List
<String
> propertyPaths
) {
3022 // TODO quickly implemented, create according dao !!!!
3023 Set
<TaxonNode
> nodes
= new HashSet
<TaxonNode
>();
3024 Set
<Classification
> classifications
= new HashSet
<Classification
>();
3025 List
<Classification
> list
= new ArrayList
<Classification
>();
3027 if (taxonBase
== null) {
3031 taxonBase
= load(taxonBase
.getUuid());
3033 if (taxonBase
instanceof Taxon
) {
3034 nodes
.addAll(((Taxon
)taxonBase
).getTaxonNodes());
3036 for (Taxon taxon
: ((Synonym
)taxonBase
).getAcceptedTaxa() ) {
3037 nodes
.addAll(taxon
.getTaxonNodes());
3040 for (TaxonNode node
: nodes
) {
3041 classifications
.add(node
.getClassification());
3043 list
.addAll(classifications
);
3048 public Synonym
changeRelatedTaxonToSynonym(Taxon fromTaxon
, Taxon toTaxon
, TaxonRelationshipType oldRelationshipType
,
3049 SynonymRelationshipType synonymRelationshipType
) throws DataChangeNoRollbackException
{
3050 // Create new synonym using concept name
3051 TaxonNameBase
<?
, ?
> synonymName
= fromTaxon
.getName();
3052 Synonym synonym
= Synonym
.NewInstance(synonymName
, fromTaxon
.getSec());
3054 // Remove concept relation from taxon
3055 toTaxon
.removeTaxon(fromTaxon
, oldRelationshipType
);
3060 // Create a new synonym for the taxon
3061 SynonymRelationship synonymRelationship
;
3062 if (synonymRelationshipType
!= null
3063 && synonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF())){
3064 synonymRelationship
= toTaxon
.addHomotypicSynonym(synonym
, null, null);
3066 synonymRelationship
= toTaxon
.addHeterotypicSynonymName(synonymName
);
3069 this.saveOrUpdate(toTaxon
);
3070 //TODO: configurator and classification
3071 TaxonDeletionConfigurator config
= new TaxonDeletionConfigurator();
3072 config
.setDeleteNameIfPossible(false);
3073 this.deleteTaxon(fromTaxon
, config
, null);
3074 return synonymRelationship
.getSynonym();
3078 public List
<String
> isDeletable(TaxonBase taxonBase
, DeleteConfiguratorBase config
){
3079 List
<String
> result
= new ArrayList
<String
>();
3080 Set
<CdmBase
> references
= commonService
.getReferencingObjectsForDeletion(taxonBase
);
3081 if (taxonBase
instanceof Taxon
){
3082 TaxonDeletionConfigurator taxonConfig
= (TaxonDeletionConfigurator
) config
;
3083 result
= isDeletableForTaxon(references
, taxonConfig
);
3085 SynonymDeletionConfigurator synonymConfig
= (SynonymDeletionConfigurator
) config
;
3086 result
= isDeletableForSynonym(references
, synonymConfig
);
3091 private List
<String
> isDeletableForSynonym(Set
<CdmBase
> references
, SynonymDeletionConfigurator config
){
3093 List
<String
> result
= new ArrayList
<String
>();
3094 for (CdmBase ref
: references
){
3095 if (!(ref
instanceof SynonymRelationship
|| ref
instanceof Taxon
|| ref
instanceof TaxonNameBase
)){
3096 message
= "The Synonym can't be deleted as long as it is referenced by " + ref
.getClass().getSimpleName() + " with id "+ ref
.getId();
3097 result
.add(message
);
3103 private List
<String
> isDeletableForTaxon(Set
<CdmBase
> references
, TaxonDeletionConfigurator config
){
3105 List
<String
> result
= new ArrayList
<String
>();
3106 for (CdmBase ref
: references
){
3107 if (!(ref
instanceof TaxonNameBase
)){
3108 if (!config
.isDeleteSynonymRelations() && (ref
instanceof SynonymRelationship
)){
3109 message
= "The Taxon can't be deleted as long as it has synonyms.";
3110 result
.add(message
);
3112 if (!config
.isDeleteDescriptions() && (ref
instanceof DescriptionBase
)){
3113 message
= "The Taxon can't be deleted as long as it has factual data.";
3114 result
.add(message
);
3117 if (!config
.isDeleteTaxonNodes() && (ref
instanceof TaxonNode
)){
3118 message
= "The Taxon can't be deleted as long as it belongs to a taxon node.";
3119 result
.add(message
);
3121 if (!config
.isDeleteTaxonRelationships() && (ref
instanceof TaxonNode
)){
3122 if (!config
.isDeleteMisappliedNamesAndInvalidDesignations() && (((TaxonRelationship
)ref
).getType().equals(TaxonRelationshipType
.MISAPPLIED_NAME_FOR())|| ((TaxonRelationship
)ref
).getType().equals(TaxonRelationshipType
.INVALID_DESIGNATION_FOR()))){
3123 message
= "The Taxon can't be deleted as long as it has misapplied names or invalid designations.";
3124 result
.add(message
);
3126 message
= "The Taxon can't be deleted as long as it belongs to a taxon node.";
3127 result
.add(message
);
3130 if (ref
instanceof PolytomousKeyNode
){
3131 message
= "The Taxon can't be deleted as long as it is referenced by a polytomous key node.";
3132 result
.add(message
);
3135 if (HibernateProxyHelper
.isInstanceOf(ref
, IIdentificationKey
.class)){
3136 message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
3137 result
.add(message
);
3142 /* //PolytomousKeyNode
3143 if (referencingObject.isInstanceOf(PolytomousKeyNode.class)){
3144 String message = "Taxon" + taxon.getTitleCache() + " can't be deleted as it is used in polytomous key node";
3149 if (ref
.isInstanceOf(TaxonInteraction
.class)){
3150 message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
3151 result
.add(message
);
3155 if (ref
.isInstanceOf(DeterminationEvent
.class)){
3156 message
= "Taxon can't be deleted as it is used in a determination event";
3157 result
.add(message
);
3168 public IncludedTaxaDTO
listIncludedTaxa(UUID taxonUuid
, IncludedTaxonConfiguration config
) {
3169 IncludedTaxaDTO result
= new IncludedTaxaDTO(taxonUuid
);
3171 //preliminary implementation
3173 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
3174 TaxonBase taxonBase
= find(taxonUuid
);
3175 if (taxonBase
== null){
3176 return new IncludedTaxaDTO();
3177 }else if (taxonBase
.isInstanceOf(Taxon
.class)){
3178 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
3180 }else if (taxonBase
.isInstanceOf(Synonym
.class)){
3181 //TODO partial synonyms ??
3182 //TODO synonyms in general
3183 Synonym syn
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
3184 taxa
.addAll(syn
.getAcceptedTaxa());
3186 throw new IllegalArgumentException("Unhandled class " + taxonBase
.getClass().getSimpleName());
3189 Set
<Taxon
> related
= makeRelatedIncluded(taxa
, result
, config
);
3191 while((! related
.isEmpty()) && i
++ < 100){ //to avoid
3192 related
= makeRelatedIncluded(related
, result
, config
);
3199 * Computes all children and conceptually congruent and included taxa and adds them to the existingTaxa
3201 * @return the set of conceptually related taxa for further use
3204 * @param uncheckedTaxa
3205 * @param existingTaxa
3209 private Set
<Taxon
> makeRelatedIncluded(Set
<Taxon
> uncheckedTaxa
, IncludedTaxaDTO existingTaxa
, IncludedTaxonConfiguration config
) {
3212 Set
<TaxonNode
> taxonNodes
= new HashSet
<TaxonNode
>();
3213 for (Taxon taxon
: uncheckedTaxa
){
3214 taxonNodes
.addAll(taxon
.getTaxonNodes());
3217 Set
<Taxon
> children
= new HashSet
<Taxon
>();
3218 if (! config
.onlyCongruent
){
3219 for (TaxonNode node
: taxonNodes
){
3220 List
<TaxonNode
> childNodes
= nodeService
.loadChildNodesOfTaxonNode(node
, null, true, false);
3221 for (TaxonNode child
: childNodes
){
3222 children
.add(child
.getTaxon());
3225 children
.remove(null); // just to be on the save side
3228 Iterator
<Taxon
> it
= children
.iterator();
3229 while(it
.hasNext()){
3230 UUID uuid
= it
.next().getUuid();
3231 if (existingTaxa
.contains(uuid
)){
3234 existingTaxa
.addIncludedTaxon(uuid
, new ArrayList
<UUID
>(), false);
3239 Set
<Taxon
> uncheckedAndChildren
= new HashSet
<Taxon
>(uncheckedTaxa
);
3240 uncheckedAndChildren
.addAll(children
);
3242 Set
<Taxon
> relatedTaxa
= makeConceptIncludedTaxa(uncheckedAndChildren
, existingTaxa
, config
);
3245 Set
<Taxon
> result
= new HashSet
<Taxon
>(relatedTaxa
);
3250 * Computes all conceptually congruent or included taxa and adds them to the existingTaxa data structure.
3251 * @return the set of these computed taxa
3253 private Set
<Taxon
> makeConceptIncludedTaxa(Set
<Taxon
> unchecked
, IncludedTaxaDTO existingTaxa
, IncludedTaxonConfiguration config
) {
3254 Set
<Taxon
> result
= new HashSet
<Taxon
>();
3256 for (Taxon taxon
: unchecked
){
3257 Set
<TaxonRelationship
> fromRelations
= taxon
.getRelationsFromThisTaxon();
3258 Set
<TaxonRelationship
> toRelations
= taxon
.getRelationsToThisTaxon();
3260 for (TaxonRelationship fromRel
: fromRelations
){
3261 if (config
.includeDoubtful
== false && fromRel
.isDoubtful()){
3264 if (fromRel
.getType().equals(TaxonRelationshipType
.CONGRUENT_TO()) ||
3265 !config
.onlyCongruent
&& fromRel
.getType().equals(TaxonRelationshipType
.INCLUDES()) ||
3266 !config
.onlyCongruent
&& fromRel
.getType().equals(TaxonRelationshipType
.CONGRUENT_OR_INCLUDES())
3268 result
.add(fromRel
.getToTaxon());
3272 for (TaxonRelationship toRel
: toRelations
){
3273 if (config
.includeDoubtful
== false && toRel
.isDoubtful()){
3276 if (toRel
.getType().equals(TaxonRelationshipType
.CONGRUENT_TO())){
3277 result
.add(toRel
.getFromTaxon());
3282 Iterator
<Taxon
> it
= result
.iterator();
3283 while(it
.hasNext()){
3284 UUID uuid
= it
.next().getUuid();
3285 if (existingTaxa
.contains(uuid
)){
3288 existingTaxa
.addIncludedTaxon(uuid
, new ArrayList
<UUID
>(), false);
3294 public List
<TaxonBase
> findTaxaByName(MatchingTaxonConfigurator config
){
3295 List
<TaxonBase
> taxonList
= dao
.getTaxaByName(true, false, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, 0, config
.getPropertyPath());