3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.cdm
.api
.service
;
13 import java
.io
.IOException
;
14 import java
.util
.ArrayList
;
15 import java
.util
.EnumSet
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
21 import java
.util
.UUID
;
23 import org
.apache
.log4j
.Logger
;
24 import org
.apache
.lucene
.index
.CorruptIndexException
;
25 import org
.apache
.lucene
.index
.IndexReader
;
26 import org
.apache
.lucene
.queryParser
.ParseException
;
27 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
28 import org
.apache
.lucene
.search
.BooleanQuery
;
29 import org
.apache
.lucene
.search
.IndexSearcher
;
30 import org
.apache
.lucene
.search
.Query
;
31 import org
.apache
.lucene
.search
.SortField
;
32 import org
.apache
.lucene
.search
.join
.JoinUtil
;
33 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
34 import org
.springframework
.stereotype
.Service
;
35 import org
.springframework
.transaction
.annotation
.Transactional
;
37 import eu
.etaxonomy
.cdm
.api
.service
.config
.IFindTaxaAndNamesConfigurator
;
38 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
39 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
40 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
41 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
42 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
43 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
44 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
45 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearch
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearchException
;
49 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
50 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
.TopGroupsWithMaxScore
;
51 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
52 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
53 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
54 import eu
.etaxonomy
.cdm
.api
.service
.util
.TaxonRelationshipEdge
;
55 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
56 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
57 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
58 import eu
.etaxonomy
.cdm
.hibernate
.search
.GroupByTaxonClassBridge
;
59 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
60 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
61 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
62 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
63 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
64 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
65 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
66 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
67 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
68 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
69 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
70 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
71 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
72 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
73 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
74 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
75 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
76 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
77 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
78 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
79 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
80 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
81 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
82 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
83 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
84 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
85 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
86 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
87 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
88 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
89 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
90 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
91 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
92 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
93 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
94 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
95 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
96 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
97 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
98 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
99 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
100 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
101 import eu
.etaxonomy
.cdm
.persistence
.dao
.AbstractBeanInitializer
;
102 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
103 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
104 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
105 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
106 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
107 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
108 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
109 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
110 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
111 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
115 * @author a.kohlbecker
120 @Transactional(readOnly
= true)
121 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
122 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
124 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
126 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
128 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
132 private ITaxonNameDao nameDao
;
135 private INameService nameService
;
138 private ICdmGenericDao genericDao
;
141 private IDescriptionService descriptionService
;
144 private IOrderedTermVocabularyDao orderedVocabularyDao
;
147 private IOccurrenceDao occurrenceDao
;
150 private AbstractBeanInitializer beanInitializer
;
152 private static IndexSearcher taxonRelationshipSearcher
;
157 public TaxonServiceImpl(){
158 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
162 * FIXME Candidate for harmonization
163 * rename searchByName ?
166 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
167 return dao
.getTaxaByName(name
, sec
);
171 * FIXME Candidate for harmonization
172 * list(Synonym.class, ...)
174 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
177 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
178 return dao
.getAllSynonyms(limit
, start
);
182 * FIXME Candidate for harmonization
183 * list(Taxon.class, ...)
185 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
188 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
189 return dao
.getAllTaxa(limit
, start
);
193 * FIXME Candidate for harmonization
194 * merge with getRootTaxa(Reference sec, ..., ...)
196 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
199 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
200 if (cdmFetch
== null){
201 cdmFetch
= CdmFetch
.NO_FETCH();
203 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
208 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
211 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
212 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
216 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
219 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
220 return dao
.getAllRelationships(limit
, start
);
224 * FIXME Candidate for harmonization
225 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
229 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
231 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
232 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
233 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
234 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
235 return taxonRelTypeVocabulary
;
242 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
245 @Transactional(readOnly
= false)
246 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
248 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
249 synonymName
.removeTaxonBase(synonym
);
250 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
251 taxonName
.removeTaxonBase(acceptedTaxon
);
253 synonym
.setName(taxonName
);
254 acceptedTaxon
.setName(synonymName
);
256 // the accepted taxon needs a new uuid because the concept has changed
257 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
258 //acceptedTaxon.setUuid(UUID.randomUUID());
263 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
265 //TODO correct delete handling still needs to be implemented / checked
267 @Transactional(readOnly
= false)
268 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
270 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
271 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
272 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
274 //check synonym is not homotypic
275 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
276 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
277 throw new HomotypicalGroupChangeException(message
);
280 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
282 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
283 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
285 for (Synonym heteroSynonym
: heteroSynonyms
){
286 if (synonym
.equals(heteroSynonym
)){
287 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
289 //move synonyms in same homotypic group to new accepted taxon
290 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
294 //synonym.getName().removeTaxonBase(synonym);
295 //TODO correct delete handling still needs to be implemented / checked
297 // deleteSynonym(synonym, taxon, false);
300 this.delete(synonym
);
302 } catch (Exception e
) {
303 logger
.info("Can't delete old synonym from database");
307 return newAcceptedTaxon
;
312 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
314 // Get name from synonym
315 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
317 // remove synonym from taxon
318 toTaxon
.removeSynonym(synonym
);
320 // Create a taxon with synonym name
321 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
323 // Add taxon relation
324 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
326 // since we are swapping names, we have to detach the name from the synonym completely.
327 // Otherwise the synonym will still be in the list of typified names.
328 synonym
.getName().removeTaxonBase(synonym
);
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
);
504 * @param includeRelationships
508 * @param propertyPaths
509 * @return an List which is not specifically ordered
512 public Set
<Taxon
> listRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Integer maxDepth
,
513 Integer limit
, Integer start
, List
<String
> propertyPaths
) {
515 Set
<Taxon
> relatedTaxa
= collectRelatedTaxa(taxon
, includeRelationships
, new HashSet
<Taxon
>(), maxDepth
);
516 relatedTaxa
.remove(taxon
);
517 beanInitializer
.initializeAll(relatedTaxa
, propertyPaths
);
523 * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the
524 * <code>taxon</code> supplied as parameter.
527 * @param includeRelationships
529 * @param maxDepth can be <code>null</code> for infinite depth
532 private Set
<Taxon
> collectRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Set
<Taxon
> taxa
, Integer maxDepth
) {
538 if(maxDepth
!= null) {
541 if(logger
.isDebugEnabled()){
542 logger
.debug("collecting related taxa for " + taxon
+ " with maxDepth=" + maxDepth
);
544 List
<TaxonRelationship
> taxonRelationships
= dao
.getTaxonRelationships(taxon
, null, null, null, null, null, null);
545 for (TaxonRelationship taxRel
: taxonRelationships
) {
548 if (taxRel
.getToTaxon() == null || taxRel
.getFromTaxon() == null || taxRel
.getType() == null) {
551 // filter by includeRelationships
552 for (TaxonRelationshipEdge relationshipEdgeFilter
: includeRelationships
) {
553 if ( relationshipEdgeFilter
.getTaxonRelationshipType().equals(taxRel
.getType()) ) {
554 if (relationshipEdgeFilter
.getDirections().contains(Direction
.relatedTo
) && !taxa
.contains(taxRel
.getToTaxon())) {
555 if(logger
.isDebugEnabled()){
556 logger
.debug(maxDepth
+ ": " + taxon
.getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxRel
.getToTaxon().getTitleCache());
558 taxa
.add(taxRel
.getToTaxon());
559 if(maxDepth
== null || maxDepth
> 0) {
560 taxa
.addAll(collectRelatedTaxa(taxRel
.getToTaxon(), includeRelationships
, taxa
, maxDepth
));
563 if(relationshipEdgeFilter
.getDirections().contains(Direction
.relatedFrom
) && !taxa
.contains(taxRel
.getFromTaxon())) {
564 taxa
.add(taxRel
.getFromTaxon());
565 if(logger
.isDebugEnabled()){
566 logger
.debug(maxDepth
+ ": " +taxRel
.getFromTaxon().getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxon
.getTitleCache() );
568 if(maxDepth
== null || maxDepth
> 0) {
569 taxa
.addAll(collectRelatedTaxa(taxRel
.getFromTaxon(), includeRelationships
, taxa
, maxDepth
));
579 * @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)
582 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
583 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
585 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
586 if(numberOfResults
> 0) { // no point checking again
587 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
590 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
594 * @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)
597 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
598 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
600 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
601 if(numberOfResults
> 0) { // no point checking again
602 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
605 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
609 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
612 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
613 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
614 return t
.getHomotypicSynonymsByHomotypicGroup();
618 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
621 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
622 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
623 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
624 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
625 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
626 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
628 return heterotypicSynonymyGroups
;
632 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
634 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
635 // Class<? extends TaxonBase> clazz = null;
636 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
637 // clazz = TaxonBase.class;
638 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
639 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
640 // } else if(configurator.isDoTaxa()) {
641 // clazz = Taxon.class;
642 // //propertyPath = configurator.getTaxonPropertyPath();
643 // } else if (configurator.isDoSynonyms()) {
644 // clazz = Synonym.class;
645 // //propertyPath = configurator.getSynonymPropertyPath();
649 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
654 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
657 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
659 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
660 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
661 List
<TaxonBase
> taxa
= null;
664 long numberTaxaResults
= 0L;
667 List
<String
> propertyPath
= new ArrayList
<String
>();
668 if(configurator
.getTaxonPropertyPath() != null){
669 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
673 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
674 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
676 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
677 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
678 configurator
.getNamedAreas());
681 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
682 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
683 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
684 configurator
.getMatchMode(), configurator
.getNamedAreas(),
685 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
689 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
692 results
.addAll(taxa
);
695 numberOfResults
+= numberTaxaResults
;
697 // Names without taxa
698 if (configurator
.isDoNamesWithoutTaxa()) {
699 int numberNameResults
= 0;
701 List
<?
extends TaxonNameBase
<?
,?
>> names
=
702 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
703 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
704 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
705 if (names
.size() > 0) {
706 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
707 if (taxonName
.getTaxonBases().size() == 0) {
708 results
.add(taxonName
);
712 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
713 numberOfResults
+= numberNameResults
;
717 // Taxa from common names
719 if (configurator
.isDoTaxaByCommonNames()) {
720 taxa
= new ArrayList
<TaxonBase
>();
721 numberTaxaResults
= 0;
722 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
723 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
725 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
726 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
727 for( Object
[] entry
: commonNameResults
) {
728 taxa
.add((TaxonBase
) entry
[0]);
732 results
.addAll(taxa
);
734 numberOfResults
+= numberTaxaResults
;
738 return new DefaultPagerImpl
<IdentifiableEntity
>
739 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
742 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
743 return dao
.getUuidAndTitleCache();
747 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
750 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
751 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
752 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
753 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
754 for (TaxonDescription taxDesc
: descriptions
){
755 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
756 for (DescriptionElementBase descElem
: elements
){
757 for(Media media
: descElem
.getMedia()){
759 //find the best matching representation
760 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
769 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
772 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, boolean limitToGalleries
, List
<String
> propertyPath
){
773 return listMedia(taxon
, includeRelationships
, limitToGalleries
, true, false, false, propertyPath
);
778 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)
781 public List
<Media
> listMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
782 Boolean limitToGalleries
, Boolean includeTaxonDescriptions
, Boolean includeOccurrences
,
783 Boolean includeTaxonNameDescriptions
, List
<String
> propertyPath
) {
785 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
786 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
788 if (limitToGalleries
== null) {
789 limitToGalleries
= false;
792 // --- resolve related taxa
793 if (includeRelationships
!= null) {
794 taxa
= listRelatedTaxa(taxon
, includeRelationships
, null, null, null, null);
797 taxa
.add((Taxon
) dao
.load(taxon
.getUuid()));
799 if(includeTaxonDescriptions
!= null && includeTaxonDescriptions
){
800 List
<TaxonDescription
> taxonDescriptions
= new ArrayList
<TaxonDescription
>();
801 // --- TaxonDescriptions
802 for (Taxon t
: taxa
) {
803 taxonDescriptions
.addAll(descriptionService
.listTaxonDescriptions(t
, null, null, null, null, propertyPath
));
805 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
806 if (!limitToGalleries
|| taxonDescription
.isImageGallery()) {
807 for (DescriptionElementBase element
: taxonDescription
.getElements()) {
808 for (Media media
: element
.getMedia()) {
809 taxonMedia
.add(media
);
816 if(includeOccurrences
!= null && includeOccurrences
) {
817 Set
<SpecimenOrObservationBase
> specimensOrObservations
= new HashSet
<SpecimenOrObservationBase
>();
819 for (Taxon t
: taxa
) {
820 specimensOrObservations
.addAll(occurrenceDao
.listByAssociatedTaxon(null, t
, null, null, null, null));
822 for (SpecimenOrObservationBase occurrence
: specimensOrObservations
) {
824 taxonMedia
.addAll(occurrence
.getMedia());
826 // SpecimenDescriptions
827 Set
<SpecimenDescription
> specimenDescriptions
= occurrence
.getSpecimenDescriptions();
828 for (DescriptionBase specimenDescription
: specimenDescriptions
) {
829 if (!limitToGalleries
|| specimenDescription
.isImageGallery()) {
830 Set
<DescriptionElementBase
> elements
= specimenDescription
.getElements();
831 for (DescriptionElementBase element
: elements
) {
832 for (Media media
: element
.getMedia()) {
833 taxonMedia
.add(media
);
840 if (occurrence
instanceof DerivedUnitBase
) {
841 if (((DerivedUnitBase
) occurrence
).getCollection() != null){
842 taxonMedia
.addAll(((DerivedUnitBase
) occurrence
).getCollection().getMedia());
847 if (occurrence
instanceof DnaSample
) {
848 Set
<Sequence
> sequences
= ((DnaSample
) occurrence
).getSequences();
849 for (Sequence sequence
: sequences
) {
850 taxonMedia
.addAll(sequence
.getChromatograms());
857 if(includeTaxonNameDescriptions
!= null && includeTaxonNameDescriptions
) {
858 // --- TaxonNameDescription
859 Set
<TaxonNameDescription
> nameDescriptions
= new HashSet
<TaxonNameDescription
>();
860 for (Taxon t
: taxa
) {
861 nameDescriptions
.addAll(t
.getName().getDescriptions());
863 for(TaxonNameDescription nameDescription
: nameDescriptions
){
864 if (!limitToGalleries
|| nameDescription
.isImageGallery()) {
865 Set
<DescriptionElementBase
> elements
= nameDescription
.getElements();
866 for (DescriptionElementBase element
: elements
) {
867 for (Media media
: element
.getMedia()) {
868 taxonMedia
.add(media
);
875 beanInitializer
.initializeAll(taxonMedia
, propertyPath
);
880 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
883 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
884 return this.dao
.listByIds(listOfIDs
, null, null, null, null);
888 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
891 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
892 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
896 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
899 public int countAllRelationships() {
900 return this.dao
.countAllRelationships();
907 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
910 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
911 return this.dao
.findIdenticalTaxonNames(propertyPath
);
916 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
919 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
921 config
= new TaxonDeletionConfigurator();
925 if (! config
.isDeleteTaxonNodes()){
926 if (taxon
.getTaxonNodes().size() > 0){
927 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
928 throw new ReferencedObjectUndeletableException(message
);
933 // SynonymRelationShip
934 if (config
.isDeleteSynonymRelations()){
935 boolean removeSynonymNameFromHomotypicalGroup
= false;
936 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
937 Synonym synonym
= synRel
.getSynonym();
938 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
939 if (config
.isDeleteSynonymsIfPossible()){
941 boolean newHomotypicGroupIfNeeded
= true;
942 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
944 deleteSynonymRelationships(synonym
, taxon
);
950 if (! config
.isDeleteTaxonRelationships()){
951 if (taxon
.getTaxonRelations().size() > 0){
952 String message
= "Taxon can't be deleted as it is related to another taxon. Remove taxon from all relations to other taxa prior to deletion.";
953 throw new ReferencedObjectUndeletableException(message
);
959 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
961 for (TaxonDescription desc
: descriptions
){
962 if (config
.isDeleteDescriptions()){
963 //TODO use description delete configurator ?
964 //FIXME check if description is ALWAYS deletable
965 descriptionService
.delete(desc
);
967 if (desc
.getDescribedSpecimenOrObservations().size()>0){
968 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
969 " which also describes specimens or abservations";
970 throw new ReferencedObjectUndeletableException(message
);
976 //check references with only reverse mapping
977 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
978 for (CdmBase referencingObject
: referencingObjects
){
979 //IIdentificationKeys (Media, Polytomous, MultiAccess)
980 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
981 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
982 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
983 throw new ReferencedObjectUndeletableException(message
);
988 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
989 String message
= "Taxon can't be deleted as it is used in polytomous key node";
990 throw new ReferencedObjectUndeletableException(message
);
994 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
995 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
996 throw new ReferencedObjectUndeletableException(message
);
1002 if (config
.isDeleteNameIfPossible()){
1004 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
1005 } catch (ReferencedObjectUndeletableException e
) {
1007 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
1014 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1016 @Transactional(readOnly
= false)
1018 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
1019 if (synonym
== null){
1022 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
1024 //remove synonymRelationship
1025 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
1027 taxonSet
.add(taxon
);
1029 taxonSet
.addAll(synonym
.getAcceptedTaxa());
1031 for (Taxon relatedTaxon
: taxonSet
){
1032 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
1033 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
1035 this.saveOrUpdate(synonym
);
1037 //TODO remove name from homotypical group?
1039 //remove synonym (if necessary)
1040 if (synonym
.getSynonymRelations().isEmpty()){
1041 TaxonNameBase
<?
,?
> name
= synonym
.getName();
1042 synonym
.setName(null);
1043 dao
.delete(synonym
);
1045 //remove name if possible (and required)
1046 if (name
!= null && removeNameIfPossible
){
1048 nameService
.delete(name
, new NameDeletionConfigurator());
1049 }catch (DataChangeNoRollbackException ex
){
1050 if (logger
.isDebugEnabled()) {
1051 logger
.debug("Name wasn't deleted as it is referenced");
1060 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
1063 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
1065 return this.dao
.findIdenticalNamesNew(propertyPath
);
1069 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1072 public String
getPhylumName(TaxonNameBase name
){
1073 return this.dao
.getPhylumName(name
);
1077 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
1080 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
1081 return dao
.deleteSynonymRelationships(syn
, taxon
);
1085 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
1088 public long deleteSynonymRelationships(Synonym syn
) {
1089 return dao
.deleteSynonymRelationships(syn
, null);
1094 * @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)
1097 public List
<SynonymRelationship
> listSynonymRelationships(
1098 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
1099 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
1100 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
1102 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
1103 if(numberOfResults
> 0) { // no point checking again
1104 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
1110 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
1113 public Taxon
findBestMatchingTaxon(String taxonName
) {
1114 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
1115 config
.setTaxonNameTitle(taxonName
);
1116 return findBestMatchingTaxon(config
);
1122 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
1124 Taxon bestCandidate
= null;
1126 // 1. search for acceptet taxa
1127 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1128 boolean bestCandidateMatchesSecUuid
= false;
1129 boolean bestCandidateIsInClassification
= false;
1130 int countEqualCandidates
= 0;
1131 for(TaxonBase taxonBaseCandidate
: taxonList
){
1132 if(taxonBaseCandidate
instanceof Taxon
){
1133 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
1134 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
1135 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
1137 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
1138 bestCandidate
= newCanditate
;
1139 countEqualCandidates
= 1;
1140 bestCandidateMatchesSecUuid
= true;
1144 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
1145 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
1147 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
1148 bestCandidate
= newCanditate
;
1149 countEqualCandidates
= 1;
1150 bestCandidateIsInClassification
= true;
1153 if (bestCandidate
== null){
1154 bestCandidate
= newCanditate
;
1155 countEqualCandidates
= 1;
1159 }else{ //not Taxon.class
1162 countEqualCandidates
++;
1165 if (bestCandidate
!= null){
1166 if(countEqualCandidates
> 1){
1167 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
1168 return bestCandidate
;
1170 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
1171 return bestCandidate
;
1176 // 2. search for synonyms
1177 if (config
.isIncludeSynonyms()){
1178 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1179 for(TaxonBase taxonBase
: synonymList
){
1180 if(taxonBase
instanceof Synonym
){
1181 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
1182 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
1183 if(!acceptetdCandidates
.isEmpty()){
1184 bestCandidate
= acceptetdCandidates
.iterator().next();
1185 if(acceptetdCandidates
.size() == 1){
1186 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
1187 return bestCandidate
;
1189 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
1190 return bestCandidate
;
1192 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
1198 } catch (Exception e
){
1200 e
.printStackTrace();
1203 return bestCandidate
;
1206 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
1207 UUID configClassificationUuid
= config
.getClassificationUuid();
1208 if (configClassificationUuid
== null){
1211 for (TaxonNode node
: taxon
.getTaxonNodes()){
1212 UUID classUuid
= node
.getClassification().getUuid();
1213 if (configClassificationUuid
.equals(classUuid
)){
1220 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1221 UUID configSecUuid
= config
.getSecUuid();
1222 if (configSecUuid
== null){
1225 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1226 return configSecUuid
.equals(taxonSecUuid
);
1230 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1233 public Synonym
findBestMatchingSynonym(String taxonName
) {
1234 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1235 if(! synonymList
.isEmpty()){
1236 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1237 if(synonymList
.size() == 1){
1238 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1241 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1250 * @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)
1253 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1254 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1256 Synonym synonym
= oldSynonymRelation
.getSynonym();
1257 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1258 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1259 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1260 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1261 //set default relationship type
1262 if (newSynonymRelationshipType
== null){
1263 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1265 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1267 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1268 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1269 boolean isSingleInGroup
= !(hgSize
> 1);
1271 if (! isSingleInGroup
){
1272 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1273 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1274 if (isHomotypicToAccepted
){
1275 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.";
1276 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1277 message
= String
.format(message
, homotypicRelatives
);
1278 throw new HomotypicalGroupChangeException(message
);
1280 if (! moveHomotypicGroup
){
1281 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.";
1282 throw new HomotypicalGroupChangeException(message
);
1285 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1287 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1289 SynonymRelationship result
= null;
1290 //move all synonyms to new taxon
1291 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1292 for (Synonym syn
: homotypicSynonyms
){
1293 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1294 for (SynonymRelationship synRelation
: synRelations
){
1295 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1296 Reference
<?
> newReference
= reference
;
1297 if (newReference
== null && keepReference
){
1298 newReference
= synRelation
.getCitation();
1300 String newRefDetail
= referenceDetail
;
1301 if (newRefDetail
== null && keepReference
){
1302 newRefDetail
= synRelation
.getCitationMicroReference();
1304 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1305 fromTaxon
.removeSynonymRelation(synRelation
, false);
1307 //change homotypic group of synonym if relType is 'homotypic'
1308 // if (newRelTypeIsHomotypic){
1309 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1312 if (synRelation
.equals(oldSynonymRelation
)){
1313 result
= newSynRelation
;
1319 saveOrUpdate(newTaxon
);
1320 //Assert that there is a result
1321 if (result
== null){
1322 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1323 throw new IllegalStateException(message
);
1329 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1332 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1333 return dao
.getUuidAndTitleCacheTaxon();
1337 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1340 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1341 return dao
.getUuidAndTitleCacheSynonym();
1345 * @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)
1348 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1349 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1350 Classification classification
, List
<Language
> languages
,
1351 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1354 LuceneSearch luceneSearch
= prepareFindByFullTextSearch(clazz
, queryString
, classification
, languages
, highlightFragments
);
1356 // --- execute search
1357 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1359 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1360 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1362 // --- initialize taxa, thighlight matches ....
1363 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1364 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1365 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1367 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1368 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1373 * @param queryString
1374 * @param classification
1376 * @param highlightFragments
1377 * @param directorySelectClass
1380 protected LuceneSearch
prepareFindByFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Language
> languages
,
1381 boolean highlightFragments
) {
1382 BooleanQuery finalQuery
= new BooleanQuery();
1383 BooleanQuery textQuery
= new BooleanQuery();
1385 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, TaxonBase
.class);
1386 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1388 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1389 luceneSearch
.setSortFields(sortFields
);
1391 // ---- search criteria
1392 luceneSearch
.setClazz(clazz
);
1394 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1395 textQuery
.add(queryFactory
.newDefinedTermQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1397 finalQuery
.add(textQuery
, Occur
.MUST
);
1399 if(classification
!= null){
1400 finalQuery
.add(queryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1402 luceneSearch
.setQuery(finalQuery
);
1404 if(highlightFragments
){
1405 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1407 return luceneSearch
;
1411 * Uses org.apache.lucene.search.join.JoinUtil for query time joining, alternatively
1412 * the BlockJoinQuery could be used. The latter might be more memory save but has the
1413 * drawback of requiring to do the join an indexing time.
1414 * see http://dev.e-taxonomy.eu/trac/wiki/LuceneNotes#JoinsinLucene for more information on this.
1416 * Joins TaxonRelationShip with Taxon depending on the direction of the given edge:
1418 * <li>direct, everted: {@link Direction.relatedTo}: TaxonRelationShip.relatedTo.id --> Taxon.id </li>
1419 * <li>inverse: {@link Direction.relatedFrom}: TaxonRelationShip.relatedFrom.id --> Taxon.id </li>
1422 * @param queryString
1423 * @param classification
1425 * @param highlightFragments
1428 protected LuceneSearch
prepareFindByTaxonRelationFullTextSearch(TaxonRelationshipEdge edge
, String queryString
, Classification classification
, List
<Language
> languages
,
1429 boolean highlightFragments
) {
1432 String queryTermField
;
1433 String toField
= "id"; // TaxonBase.uuid
1435 if(edge
.isBidirectional()){
1436 throw new RuntimeException("Bidirectional joining not supported!");
1439 idField
= "relatedFrom.id";
1440 queryTermField
= "relatedFrom.titleCache";
1441 } else if(edge
.isInvers()) {
1442 idField
= "relatedTo.id";
1443 queryTermField
= "relatedTo.titleCache";
1445 throw new RuntimeException("Invalid direction: " + edge
.getDirections());
1448 BooleanQuery finalQuery
= new BooleanQuery();
1449 BooleanQuery joinFromQuery
= new BooleanQuery();
1450 Query joinQuery
= null;
1452 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), TaxonBase
.class);
1453 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1455 joinFromQuery
.add(queryFactory
.newTermQuery(queryTermField
, queryString
), Occur
.MUST
);
1456 joinFromQuery
.add(queryFactory
.newEntityIdQuery("type.id", edge
.getTaxonRelationshipType()), Occur
.MUST
);
1458 // TODO move into QueryFactory if possible
1459 if(taxonRelationshipSearcher
== null){
1460 IndexReader taxonRelationshipReader
= luceneSearch
.getIndexReaderFor(TaxonRelationship
.class);
1461 taxonRelationshipSearcher
= new IndexSearcher(taxonRelationshipReader
);
1462 taxonRelationshipSearcher
.setDefaultFieldSortScoring(true, true);
1464 joinQuery
= JoinUtil
.createJoinQuery(idField
, toField
, joinFromQuery
, taxonRelationshipSearcher
);
1465 // end of possible move
1466 } catch (IOException e
) {
1470 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1471 luceneSearch
.setSortFields(sortFields
);
1473 finalQuery
.add(joinQuery
, Occur
.MUST
);
1475 if(classification
!= null){
1476 finalQuery
.add(queryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1478 luceneSearch
.setQuery(finalQuery
);
1480 if(highlightFragments
){
1481 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1483 return luceneSearch
;
1490 * @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)
1493 public Pager
<SearchResult
<TaxonBase
>> findTaxaAndNamesByFullText(
1494 EnumSet
<TaxaAndNamesSearchMode
> searchModes
, String queryString
, Classification classification
,
1495 Set
<NamedArea
> namedAreas
, List
<Language
> languages
, boolean highlightFragments
, Integer pageSize
,
1496 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
)
1497 throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
1499 // set default if parameter is null
1500 if(searchModes
== null){
1501 searchModes
= EnumSet
.of(TaxaAndNamesSearchMode
.doTaxa
);
1504 List
<LuceneSearch
> luceneSearches
= new ArrayList
<LuceneSearch
>();
1505 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1508 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) || searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1509 Class taxonBaseSubclass
= TaxonBase
.class;
1510 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && !searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1511 taxonBaseSubclass
= Taxon
.class;
1512 } else if (!searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1513 taxonBaseSubclass
= Synonym
.class;
1515 luceneSearches
.add(prepareFindByFullTextSearch(taxonBaseSubclass
, queryString
, classification
, languages
, highlightFragments
));
1516 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1518 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxaByCommonNames
)) {
1519 luceneSearches
.add(prepareByDescriptionElementFullTextSearch(CommonTaxonName
.class, queryString
, classification
, null, languages
, highlightFragments
));
1520 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1522 if(searchModes
.contains(TaxaAndNamesSearchMode
.doMisappliedNames
)) {
1524 // prepareFindByTaxonRelationFullTextSearch() is making use of JoinUtil.createJoinQuery()
1525 // which allows doing query time joins
1526 luceneSearches
.add(prepareFindByTaxonRelationFullTextSearch(
1527 new TaxonRelationshipEdge(TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), Direction
.relatedTo
),
1528 queryString
, classification
, languages
, highlightFragments
));
1529 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1532 // TODO implement area filter
1534 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneSearches
.toArray(new LuceneSearch
[luceneSearches
.size()]));
1536 // --- execute search
1537 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1539 // --- initialize taxa, highlight matches ....
1540 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1543 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1544 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1546 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1547 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1551 * @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)
1554 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1555 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1556 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1557 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1560 LuceneSearch luceneSearch
= prepareByDescriptionElementFullTextSearch(clazz
, queryString
, classification
, features
, languages
, highlightFragments
);
1562 // --- execute search
1563 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1565 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1566 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1568 // --- initialize taxa, highlight matches ....
1569 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1570 @SuppressWarnings("rawtypes")
1571 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1572 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1574 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1575 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1581 public Pager
<SearchResult
<TaxonBase
>> findByEverythingFullText(String queryString
,
1582 Classification classification
, List
<Language
> languages
, boolean highlightFragments
,
1583 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
1585 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, null, languages
, highlightFragments
);
1586 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
);
1588 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
1590 // --- execute search
1591 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1593 // --- initialize taxa, highlight matches ....
1594 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1596 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1597 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1598 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1600 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1601 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1603 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1604 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1611 * @param queryString
1612 * @param classification
1615 * @param highlightFragments
1616 * @param directorySelectClass
1619 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Feature
> features
,
1620 List
<Language
> languages
, boolean highlightFragments
) {
1621 BooleanQuery finalQuery
= new BooleanQuery();
1622 BooleanQuery textQuery
= new BooleanQuery();
1624 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, DescriptionElementBase
.class);
1625 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1627 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", SortField
.STRING
, false)};
1628 luceneSearch
.setSortFields(sortFields
);
1630 // ---- search criteria
1631 luceneSearch
.setClazz(clazz
);
1632 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1636 if(languages
== null || languages
.size() == 0){
1637 nameQuery
= queryFactory
.newTermQuery("name", queryString
);
1639 nameQuery
= new BooleanQuery();
1640 BooleanQuery languageSubQuery
= new BooleanQuery();
1641 for(Language lang
: languages
){
1642 languageSubQuery
.add(queryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString(), false), Occur
.SHOULD
);
1644 ((BooleanQuery
) nameQuery
).add(queryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
1645 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1647 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1650 // text field from TextData
1651 textQuery
.add(queryFactory
.newMultilanguageTextQuery("text", queryString
, languages
), Occur
.SHOULD
);
1653 // --- TermBase fields - by representation ----
1654 // state field from CategoricalData
1655 textQuery
.add(queryFactory
.newDefinedTermQuery("states.state", queryString
, languages
), Occur
.SHOULD
);
1657 // state field from CategoricalData
1658 textQuery
.add(queryFactory
.newDefinedTermQuery("states.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1660 // area field from Distribution
1661 textQuery
.add(queryFactory
.newDefinedTermQuery("area", queryString
, languages
), Occur
.SHOULD
);
1663 // status field from Distribution
1664 textQuery
.add(queryFactory
.newDefinedTermQuery("status", queryString
, languages
), Occur
.SHOULD
);
1666 finalQuery
.add(textQuery
, Occur
.MUST
);
1667 // --- classification ----
1669 if(classification
!= null){
1670 finalQuery
.add(queryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
1673 // --- IdentifieableEntity fields - by uuid
1674 if(features
!= null && features
.size() > 0 ){
1675 finalQuery
.add(queryFactory
.newEntityUuidQuery("feature.uuid", features
), Occur
.MUST
);
1678 // the description must be associated with a taxon
1679 finalQuery
.add(queryFactory
.newIsNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
1681 logger
.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery
.toString());
1682 luceneSearch
.setQuery(finalQuery
);
1684 if(highlightFragments
){
1685 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1687 return luceneSearch
;
1691 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1692 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1693 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1695 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1696 * or {@link MultilanguageTextFieldBridge }
1697 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1698 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1699 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1701 * TODO move to utiliy class !!!!!!!!
1703 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1705 if(stringBuilder
== null){
1706 stringBuilder
= new StringBuilder();
1708 if(languages
== null || languages
.size() == 0){
1709 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
1711 for(Language lang
: languages
){
1712 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
1715 return stringBuilder
;
1719 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1720 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1721 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1723 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1726 UUID nameUuid
= taxon
.getName().getUuid();
1727 ZoologicalName taxonName
= getZoologicalName(nameUuid
, zooHashMap
);
1728 String epithetOfTaxon
= null;
1729 String infragenericEpithetOfTaxon
= null;
1730 String infraspecificEpithetOfTaxon
= null;
1731 if (taxonName
.isSpecies()){
1732 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1733 } else if (taxonName
.isInfraGeneric()){
1734 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1735 } else if (taxonName
.isInfraSpecific()){
1736 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1738 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1739 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1740 List
<String
> taxonNames
= new ArrayList
<String
>();
1742 for (TaxonNode node
: nodes
){
1743 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1744 // List<String> synonymsEpithet = new ArrayList<String>();
1746 if (node
.getClassification().equals(classification
)){
1747 if (!node
.isTopmostNode()){
1748 TaxonNode parent
= node
.getParent();
1749 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1750 TaxonNameBase
<?
,?
> parentName
= parent
.getTaxon().getName();
1751 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1752 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1753 Rank rankOfTaxon
= taxonName
.getRank();
1756 //create inferred synonyms for species, subspecies
1757 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1759 Synonym inferredEpithet
= null;
1760 Synonym inferredGenus
= null;
1761 Synonym potentialCombination
= null;
1763 List
<String
> propertyPaths
= new ArrayList
<String
>();
1764 propertyPaths
.add("synonym");
1765 propertyPaths
.add("synonym.name");
1766 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1767 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1769 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1770 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1772 List
<TaxonRelationship
> taxonRelListParent
= null;
1773 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1774 if (doWithMisappliedNames
){
1775 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1776 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1780 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1783 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1784 Synonym syn
= synonymRelationOfParent
.getSynonym();
1786 inferredEpithet
= createInferredEpithets(taxon
,
1787 zooHashMap
, taxonName
, epithetOfTaxon
,
1788 infragenericEpithetOfTaxon
,
1789 infraspecificEpithetOfTaxon
,
1790 taxonNames
, parentName
,
1794 inferredSynonyms
.add(inferredEpithet
);
1795 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1796 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1799 if (doWithMisappliedNames
){
1801 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1802 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1804 inferredEpithet
= createInferredEpithets(taxon
,
1805 zooHashMap
, taxonName
, epithetOfTaxon
,
1806 infragenericEpithetOfTaxon
,
1807 infraspecificEpithetOfTaxon
,
1808 taxonNames
, parentName
,
1811 inferredSynonyms
.add(inferredEpithet
);
1812 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1813 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1817 if (!taxonNames
.isEmpty()){
1818 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1819 ZoologicalName name
;
1820 if (!synNotInCDM
.isEmpty()){
1821 inferredSynonymsToBeRemoved
.clear();
1823 for (Synonym syn
:inferredSynonyms
){
1824 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1825 if (!synNotInCDM
.contains(name
.getNameCache())){
1826 inferredSynonymsToBeRemoved
.add(syn
);
1830 // Remove identified Synonyms from inferredSynonyms
1831 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1832 inferredSynonyms
.remove(synonym
);
1837 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1840 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1841 TaxonNameBase synName
;
1842 ZoologicalName inferredSynName
;
1844 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1845 inferredGenus
= createInferredGenus(taxon
,
1846 zooHashMap
, taxonName
, epithetOfTaxon
,
1847 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1849 inferredSynonyms
.add(inferredGenus
);
1850 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1851 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1856 if (doWithMisappliedNames
){
1858 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1859 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1860 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1862 inferredSynonyms
.add(inferredGenus
);
1863 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1864 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1869 if (!taxonNames
.isEmpty()){
1870 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1871 ZoologicalName name
;
1872 if (!synNotInCDM
.isEmpty()){
1873 inferredSynonymsToBeRemoved
.clear();
1875 for (Synonym syn
:inferredSynonyms
){
1876 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1877 if (!synNotInCDM
.contains(name
.getNameCache())){
1878 inferredSynonymsToBeRemoved
.add(syn
);
1882 // Remove identified Synonyms from inferredSynonyms
1883 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1884 inferredSynonyms
.remove(synonym
);
1889 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1891 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1892 ZoologicalName inferredSynName
;
1893 //for all synonyms of the parent...
1894 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1895 TaxonNameBase synName
;
1896 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1897 synName
= synParent
.getName();
1899 HibernateProxyHelper
.deproxy(synParent
);
1901 // Set the sourceReference
1902 sourceReference
= synParent
.getSec();
1904 // Determine the idInSource
1905 String idInSourceParent
= getIdInSource(synParent
);
1907 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1908 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1909 String synParentInfragenericName
= null;
1910 String synParentSpecificEpithet
= null;
1912 if (parentSynZooName
.isInfraGeneric()){
1913 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1915 if (parentSynZooName
.isSpecies()){
1916 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1919 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1920 synonymsGenus.put(synGenusName, idInSource);
1923 //for all synonyms of the taxon
1925 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1927 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1928 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1929 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1931 synParentInfragenericName
,
1932 synParentSpecificEpithet
, syn
, zooHashMap
);
1934 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1935 inferredSynonyms
.add(potentialCombination
);
1936 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1937 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1944 if (doWithMisappliedNames
){
1946 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1948 TaxonNameBase misappliedParentName
;
1950 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1951 misappliedParentName
= misappliedParent
.getName();
1953 HibernateProxyHelper
.deproxy(misappliedParent
);
1955 // Set the sourceReference
1956 sourceReference
= misappliedParent
.getSec();
1958 // Determine the idInSource
1959 String idInSourceParent
= getIdInSource(misappliedParent
);
1961 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1962 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1963 String synParentInfragenericName
= null;
1964 String synParentSpecificEpithet
= null;
1966 if (parentSynZooName
.isInfraGeneric()){
1967 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1969 if (parentSynZooName
.isSpecies()){
1970 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1974 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1975 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1976 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1977 potentialCombination
= createPotentialCombination(
1978 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1980 synParentInfragenericName
,
1981 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1984 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1985 inferredSynonyms
.add(potentialCombination
);
1986 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1987 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1992 if (!taxonNames
.isEmpty()){
1993 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1994 ZoologicalName name
;
1995 if (!synNotInCDM
.isEmpty()){
1996 inferredSynonymsToBeRemoved
.clear();
1997 for (Synonym syn
:inferredSynonyms
){
1999 name
= (ZoologicalName
) syn
.getName();
2000 }catch (ClassCastException e
){
2001 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2003 if (!synNotInCDM
.contains(name
.getNameCache())){
2004 inferredSynonymsToBeRemoved
.add(syn
);
2007 // Remove identified Synonyms from inferredSynonyms
2008 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2009 inferredSynonyms
.remove(synonym
);
2015 logger
.info("The synonymrelationship type is not defined.");
2016 return inferredSynonyms
;
2023 return inferredSynonyms
;
2026 private Synonym
createPotentialCombination(String idInSourceParent
,
2027 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
2028 String synParentInfragenericName
, String synParentSpecificEpithet
,
2029 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2030 Synonym potentialCombination
;
2031 Reference sourceReference
;
2032 ZoologicalName inferredSynName
;
2033 HibernateProxyHelper
.deproxy(syn
);
2035 // Set sourceReference
2036 sourceReference
= syn
.getSec();
2037 if (sourceReference
== null){
2038 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2040 if (!parentSynZooName
.getTaxa().isEmpty()){
2041 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
2043 sourceReference
= taxon
.getSec();
2046 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
2048 String synTaxonInfraSpecificName
= null;
2050 if (parentSynZooName
.isSpecies()){
2051 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
2054 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
2055 synonymsEpithet.add(epithetName);
2058 //create potential combinations...
2059 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
2061 inferredSynName
.setGenusOrUninomial(synParentGenus
);
2062 if (zooSynName
.isSpecies()){
2063 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
2064 if (parentSynZooName
.isInfraGeneric()){
2065 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2068 if (zooSynName
.isInfraSpecific()){
2069 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
2070 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
2072 if (parentSynZooName
.isInfraGeneric()){
2073 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2077 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
2079 // Set the sourceReference
2080 potentialCombination
.setSec(sourceReference
);
2083 // Determine the idInSource
2084 String idInSourceSyn
= getIdInSource(syn
);
2086 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
2087 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2088 inferredSynName
.addSource(originalSource
);
2089 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2090 potentialCombination
.addSource(originalSource
);
2093 inferredSynName
.generateTitle();
2095 return potentialCombination
;
2098 private Synonym
createInferredGenus(Taxon taxon
,
2099 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2100 String epithetOfTaxon
, String genusOfTaxon
,
2101 List
<String
> taxonNames
, ZoologicalName zooParentName
,
2104 Synonym inferredGenus
;
2105 TaxonNameBase synName
;
2106 ZoologicalName inferredSynName
;
2107 synName
=syn
.getName();
2108 HibernateProxyHelper
.deproxy(syn
);
2110 // Determine the idInSource
2111 String idInSourceSyn
= getIdInSource(syn
);
2112 String idInSourceTaxon
= getIdInSource(taxon
);
2113 // Determine the sourceReference
2114 Reference sourceReference
= syn
.getSec();
2116 //logger.warn(sourceReference.getTitleCache());
2118 synName
= syn
.getName();
2119 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2120 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
2121 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
2122 synonymsEpithet.add(synSpeciesEpithetName);
2125 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2126 //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...
2129 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
2130 if (zooParentName
.isInfraGeneric()){
2131 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
2134 if (taxonName
.isSpecies()){
2135 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
2137 if (taxonName
.isInfraSpecific()){
2138 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2139 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
2143 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
2145 // Set the sourceReference
2146 inferredGenus
.setSec(sourceReference
);
2148 // Add the original source
2149 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
2150 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2151 inferredGenus
.addSource(originalSource
);
2153 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2154 inferredSynName
.addSource(originalSource
);
2155 originalSource
= null;
2158 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
2159 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2160 inferredGenus
.addSource(originalSource
);
2162 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2163 inferredSynName
.addSource(originalSource
);
2164 originalSource
= null;
2167 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
2169 inferredSynName
.generateTitle();
2172 return inferredGenus
;
2175 private Synonym
createInferredEpithets(Taxon taxon
,
2176 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2177 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
2178 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
2179 TaxonNameBase parentName
, TaxonBase syn
) {
2181 Synonym inferredEpithet
;
2182 TaxonNameBase
<?
,?
> synName
;
2183 ZoologicalName inferredSynName
;
2184 HibernateProxyHelper
.deproxy(syn
);
2186 // Determine the idInSource
2187 String idInSourceSyn
= getIdInSource(syn
);
2188 String idInSourceTaxon
= getIdInSource(taxon
);
2189 // Determine the sourceReference
2190 Reference
<?
> sourceReference
= syn
.getSec();
2192 if (sourceReference
== null){
2193 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2195 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
2196 sourceReference
= taxon
.getSec();
2199 synName
= syn
.getName();
2200 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2201 String synGenusName
= zooSynName
.getGenusOrUninomial();
2202 String synInfraGenericEpithet
= null;
2203 String synSpecificEpithet
= null;
2205 if (zooSynName
.getInfraGenericEpithet() != null){
2206 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
2209 if (zooSynName
.isInfraSpecific()){
2210 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
2213 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2214 synonymsGenus.put(synGenusName, idInSource);
2217 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2219 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
2220 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
2221 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
2223 inferredSynName
.setGenusOrUninomial(synGenusName
);
2225 if (parentName
.isInfraGeneric()){
2226 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
2228 if (taxonName
.isSpecies()){
2229 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2230 }else if (taxonName
.isInfraSpecific()){
2231 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
2232 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
2235 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
2237 // Set the sourceReference
2238 inferredEpithet
.setSec(sourceReference
);
2240 /* Add the original source
2241 if (idInSource != null) {
2242 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
2245 Reference citation = getCitation(syn);
2246 if (citation != null) {
2247 originalSource.setCitation(citation);
2248 inferredEpithet.addSource(originalSource);
2251 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
2254 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2256 inferredEpithet
.addSource(originalSource
);
2258 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2260 inferredSynName
.addSource(originalSource
);
2264 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
2266 inferredSynName
.generateTitle();
2267 return inferredEpithet
;
2271 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
2272 * Very likely only useful for createInferredSynonyms().
2277 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2278 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
2279 if (taxonName
== null) {
2280 taxonName
= zooHashMap
.get(uuid
);
2286 * Returns the idInSource for a given Synonym.
2289 private String
getIdInSource(TaxonBase taxonBase
) {
2290 String idInSource
= null;
2291 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
2292 if (sources
.size() == 1) {
2293 IdentifiableSource source
= sources
.iterator().next();
2294 if (source
!= null) {
2295 idInSource
= source
.getIdInSource();
2297 } else if (sources
.size() > 1) {
2300 for (IdentifiableSource source
: sources
) {
2301 idInSource
+= source
.getIdInSource();
2302 if (count
< sources
.size()) {
2307 } else if (sources
.size() == 0){
2308 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
2317 * Returns the citation for a given Synonym.
2320 private Reference
getCitation(Synonym syn
) {
2321 Reference citation
= null;
2322 Set
<IdentifiableSource
> sources
= syn
.getSources();
2323 if (sources
.size() == 1) {
2324 IdentifiableSource source
= sources
.iterator().next();
2325 if (source
!= null) {
2326 citation
= source
.getCitation();
2328 } else if (sources
.size() > 1) {
2329 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
2336 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
2337 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2339 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
2340 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
2341 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
2343 return inferredSynonyms
;
2347 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listClassifications(eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)
2350 public List
<Classification
> listClassifications(TaxonBase taxonBase
, Integer limit
, Integer start
, List
<String
> propertyPaths
) {
2352 // TODO quickly implemented, create according dao !!!!
2353 Set
<TaxonNode
> nodes
= new HashSet
<TaxonNode
>();
2354 Set
<Classification
> classifications
= new HashSet
<Classification
>();
2355 List
<Classification
> list
= new ArrayList
<Classification
>();
2357 if (taxonBase
== null) {
2361 taxonBase
= load(taxonBase
.getUuid());
2363 if (taxonBase
instanceof Taxon
) {
2364 nodes
.addAll(((Taxon
)taxonBase
).getTaxonNodes());
2366 for (Taxon taxon
: ((Synonym
)taxonBase
).getAcceptedTaxa() ) {
2367 nodes
.addAll(taxon
.getTaxonNodes());
2370 for (TaxonNode node
: nodes
) {
2371 classifications
.add(node
.getClassification());
2373 list
.addAll(classifications
);