3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.cdm
.api
.service
;
13 import java
.io
.IOException
;
14 import java
.util
.ArrayList
;
15 import java
.util
.EnumSet
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
21 import java
.util
.UUID
;
23 import org
.apache
.log4j
.Logger
;
24 import org
.apache
.lucene
.index
.CorruptIndexException
;
25 import org
.apache
.lucene
.queryParser
.ParseException
;
26 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
27 import org
.apache
.lucene
.search
.BooleanFilter
;
28 import org
.apache
.lucene
.search
.BooleanQuery
;
29 import org
.apache
.lucene
.search
.DocIdSet
;
30 import org
.apache
.lucene
.search
.Query
;
31 import org
.apache
.lucene
.search
.QueryWrapperFilter
;
32 import org
.apache
.lucene
.search
.SortField
;
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
.DocIdBitSetPrinter
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
49 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearch
;
50 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearchException
;
51 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
52 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
.TopGroupsWithMaxScore
;
53 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
54 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
55 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
56 import eu
.etaxonomy
.cdm
.api
.service
.util
.TaxonRelationshipEdge
;
57 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
58 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
59 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
60 import eu
.etaxonomy
.cdm
.hibernate
.search
.GroupByTaxonClassBridge
;
61 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
62 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
63 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
64 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
65 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
66 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
67 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
68 import eu
.etaxonomy
.cdm
.model
.common
.OriginalSourceType
;
69 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
70 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
71 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
72 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
73 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
74 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
75 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
76 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
77 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
78 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
79 import eu
.etaxonomy
.cdm
.model
.description
.PresenceAbsenceTermBase
;
80 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
81 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
82 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
83 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
84 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
85 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
86 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
87 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
88 import eu
.etaxonomy
.cdm
.model
.molecular
.Amplification
;
89 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
90 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
91 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
92 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
93 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
94 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
95 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
96 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
97 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
98 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
99 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
100 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
101 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
102 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
103 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
104 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
105 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
106 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
107 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
108 import eu
.etaxonomy
.cdm
.persistence
.dao
.AbstractBeanInitializer
;
109 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
110 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
111 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
112 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
113 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
114 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
115 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
116 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
117 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
118 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
122 * @author a.kohlbecker
127 @Transactional(readOnly
= true)
128 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
129 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
131 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
133 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
135 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
139 private ITaxonNameDao nameDao
;
142 private INameService nameService
;
145 private ICdmGenericDao genericDao
;
148 private IDescriptionService descriptionService
;
151 private IOrderedTermVocabularyDao orderedVocabularyDao
;
154 private IOccurrenceDao occurrenceDao
;
157 private AbstractBeanInitializer beanInitializer
;
160 private ILuceneIndexToolProvider luceneIndexToolProvider
;
166 public TaxonServiceImpl(){
167 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
171 * FIXME Candidate for harmonization
172 * rename searchByName ?
175 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
176 return dao
.getTaxaByName(name
, sec
);
180 * FIXME Candidate for harmonization
181 * list(Synonym.class, ...)
183 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
186 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
187 return dao
.getAllSynonyms(limit
, start
);
191 * FIXME Candidate for harmonization
192 * list(Taxon.class, ...)
194 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
197 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
198 return dao
.getAllTaxa(limit
, start
);
202 * FIXME Candidate for harmonization
203 * merge with getRootTaxa(Reference sec, ..., ...)
205 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
208 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
209 if (cdmFetch
== null){
210 cdmFetch
= CdmFetch
.NO_FETCH();
212 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
217 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
220 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
221 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
225 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
228 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
229 return dao
.getAllRelationships(limit
, start
);
233 * FIXME Candidate for harmonization
234 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
238 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
240 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
241 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
242 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
243 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
244 return taxonRelTypeVocabulary
;
251 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
254 @Transactional(readOnly
= false)
255 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
257 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
258 synonymName
.removeTaxonBase(synonym
);
259 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
260 taxonName
.removeTaxonBase(acceptedTaxon
);
262 synonym
.setName(taxonName
);
263 acceptedTaxon
.setName(synonymName
);
265 // the accepted taxon needs a new uuid because the concept has changed
266 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
267 //acceptedTaxon.setUuid(UUID.randomUUID());
272 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
274 //TODO correct delete handling still needs to be implemented / checked
276 @Transactional(readOnly
= false)
277 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
279 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
280 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
281 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
283 //check synonym is not homotypic
284 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
285 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
286 throw new HomotypicalGroupChangeException(message
);
289 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
291 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
292 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
294 for (Synonym heteroSynonym
: heteroSynonyms
){
295 if (synonym
.equals(heteroSynonym
)){
296 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
298 //move synonyms in same homotypic group to new accepted taxon
299 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
303 //synonym.getName().removeTaxonBase(synonym);
304 //TODO correct delete handling still needs to be implemented / checked
306 // deleteSynonym(synonym, taxon, false);
309 this.delete(synonym
);
311 } catch (Exception e
) {
312 logger
.info("Can't delete old synonym from database");
316 return newAcceptedTaxon
;
321 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
323 // Get name from synonym
324 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
326 // remove synonym from taxon
327 toTaxon
.removeSynonym(synonym
);
329 // Create a taxon with synonym name
330 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
332 // Add taxon relation
333 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
335 // since we are swapping names, we have to detach the name from the synonym completely.
336 // Otherwise the synonym will still be in the list of typified names.
337 synonym
.getName().removeTaxonBase(synonym
);
344 * @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)
346 @Transactional(readOnly
= false)
348 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
349 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
351 TaxonNameBase synonymName
= synonym
.getName();
352 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
356 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
357 newHomotypicalGroup
.addTypifiedName(synonymName
);
359 //remove existing basionym relationships
360 synonymName
.removeBasionyms();
362 //add basionym relationship
363 if (setBasionymRelationIfApplicable
){
364 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
365 for (TaxonNameBase basionym
: basionyms
){
366 synonymName
.addBasionym(basionym
);
370 //set synonym relationship correctly
371 // SynonymRelationship relToTaxon = null;
372 boolean relToTargetTaxonExists
= false;
373 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
374 for (SynonymRelationship rel
: existingRelations
){
375 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
376 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
377 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
378 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
379 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
380 rel
.setType(newRelationType
);
381 //TODO handle citation and microCitation
384 relToTargetTaxonExists
= true;
386 if (removeFromOtherTaxa
){
387 acceptedTaxon
.removeSynonym(synonym
, false);
393 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
394 Taxon acceptedTaxon
= targetTaxon
;
395 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
396 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
397 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
398 //TODO handle citation and microCitation
399 Reference citation
= null;
400 String microCitation
= null;
401 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
408 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
411 @Transactional(readOnly
= false)
412 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
414 clazz
= TaxonBase
.class;
416 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
421 protected void setDao(ITaxonDao dao
) {
426 * @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)
429 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
,
430 String uninomial
, String infragenericEpithet
, String specificEpithet
,
431 String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
432 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
434 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
435 if(numberOfResults
> 0) { // no point checking again
436 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
439 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
444 * @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)
447 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
448 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
450 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
451 if(numberOfResults
> 0) { // no point checking again
452 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
459 * @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)
462 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
463 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
465 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
466 if(numberOfResults
> 0) { // no point checking again
467 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
473 * @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)
476 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
477 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
479 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
480 if(numberOfResults
> 0) { // no point checking again
481 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
483 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
487 * @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)
490 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
491 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
493 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
494 if(numberOfResults
> 0) { // no point checking again
495 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
501 * @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)
504 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
505 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
507 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
508 if(numberOfResults
> 0) { // no point checking again
509 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
511 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
516 * @param includeRelationships
520 * @param propertyPaths
521 * @return an List which is not specifically ordered
524 public Set
<Taxon
> listRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Integer maxDepth
,
525 Integer limit
, Integer start
, List
<String
> propertyPaths
) {
527 Set
<Taxon
> relatedTaxa
= collectRelatedTaxa(taxon
, includeRelationships
, new HashSet
<Taxon
>(), maxDepth
);
528 relatedTaxa
.remove(taxon
);
529 beanInitializer
.initializeAll(relatedTaxa
, propertyPaths
);
535 * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the
536 * <code>taxon</code> supplied as parameter.
539 * @param includeRelationships
541 * @param maxDepth can be <code>null</code> for infinite depth
544 private Set
<Taxon
> collectRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Set
<Taxon
> taxa
, Integer maxDepth
) {
550 if(maxDepth
!= null) {
553 if(logger
.isDebugEnabled()){
554 logger
.debug("collecting related taxa for " + taxon
+ " with maxDepth=" + maxDepth
);
556 List
<TaxonRelationship
> taxonRelationships
= dao
.getTaxonRelationships(taxon
, null, null, null, null, null, null);
557 for (TaxonRelationship taxRel
: taxonRelationships
) {
560 if (taxRel
.getToTaxon() == null || taxRel
.getFromTaxon() == null || taxRel
.getType() == null) {
563 // filter by includeRelationships
564 for (TaxonRelationshipEdge relationshipEdgeFilter
: includeRelationships
) {
565 if ( relationshipEdgeFilter
.getTaxonRelationshipType().equals(taxRel
.getType()) ) {
566 if (relationshipEdgeFilter
.getDirections().contains(Direction
.relatedTo
) && !taxa
.contains(taxRel
.getToTaxon())) {
567 if(logger
.isDebugEnabled()){
568 logger
.debug(maxDepth
+ ": " + taxon
.getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxRel
.getToTaxon().getTitleCache());
570 taxa
.add(taxRel
.getToTaxon());
571 if(maxDepth
== null || maxDepth
> 0) {
572 taxa
.addAll(collectRelatedTaxa(taxRel
.getToTaxon(), includeRelationships
, taxa
, maxDepth
));
575 if(relationshipEdgeFilter
.getDirections().contains(Direction
.relatedFrom
) && !taxa
.contains(taxRel
.getFromTaxon())) {
576 taxa
.add(taxRel
.getFromTaxon());
577 if(logger
.isDebugEnabled()){
578 logger
.debug(maxDepth
+ ": " +taxRel
.getFromTaxon().getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxon
.getTitleCache() );
580 if(maxDepth
== null || maxDepth
> 0) {
581 taxa
.addAll(collectRelatedTaxa(taxRel
.getFromTaxon(), includeRelationships
, taxa
, maxDepth
));
591 * @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)
594 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
595 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
597 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
598 if(numberOfResults
> 0) { // no point checking again
599 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
602 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
606 * @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)
609 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
610 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
612 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
613 if(numberOfResults
> 0) { // no point checking again
614 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
617 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
621 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
624 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
625 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
626 return t
.getHomotypicSynonymsByHomotypicGroup();
630 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
633 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
634 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
635 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
636 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
637 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
638 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
640 return heterotypicSynonymyGroups
;
644 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
646 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
647 // Class<? extends TaxonBase> clazz = null;
648 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
649 // clazz = TaxonBase.class;
650 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
651 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
652 // } else if(configurator.isDoTaxa()) {
653 // clazz = Taxon.class;
654 // //propertyPath = configurator.getTaxonPropertyPath();
655 // } else if (configurator.isDoSynonyms()) {
656 // clazz = Synonym.class;
657 // //propertyPath = configurator.getSynonymPropertyPath();
661 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
666 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
669 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
671 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
672 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
673 List
<TaxonBase
> taxa
= null;
676 long numberTaxaResults
= 0L;
679 List
<String
> propertyPath
= new ArrayList
<String
>();
680 if(configurator
.getTaxonPropertyPath() != null){
681 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
685 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
686 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
688 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
689 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
690 configurator
.getNamedAreas());
693 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
694 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
695 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
696 configurator
.getMatchMode(), configurator
.getNamedAreas(),
697 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
701 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
704 results
.addAll(taxa
);
707 numberOfResults
+= numberTaxaResults
;
709 // Names without taxa
710 if (configurator
.isDoNamesWithoutTaxa()) {
711 int numberNameResults
= 0;
713 List
<?
extends TaxonNameBase
<?
,?
>> names
=
714 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
715 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
716 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
717 if (names
.size() > 0) {
718 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
719 if (taxonName
.getTaxonBases().size() == 0) {
720 results
.add(taxonName
);
724 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
725 numberOfResults
+= numberNameResults
;
729 // Taxa from common names
731 if (configurator
.isDoTaxaByCommonNames()) {
732 taxa
= new ArrayList
<TaxonBase
>();
733 numberTaxaResults
= 0;
734 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
735 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
737 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
738 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
739 for( Object
[] entry
: commonNameResults
) {
740 taxa
.add((TaxonBase
) entry
[0]);
744 results
.addAll(taxa
);
746 numberOfResults
+= numberTaxaResults
;
750 return new DefaultPagerImpl
<IdentifiableEntity
>
751 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
754 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
755 return dao
.getUuidAndTitleCache();
759 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
762 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
763 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
764 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
765 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
766 for (TaxonDescription taxDesc
: descriptions
){
767 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
768 for (DescriptionElementBase descElem
: elements
){
769 for(Media media
: descElem
.getMedia()){
771 //find the best matching representation
772 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
781 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
784 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, boolean limitToGalleries
, List
<String
> propertyPath
){
785 return listMedia(taxon
, includeRelationships
, limitToGalleries
, true, false, false, propertyPath
);
790 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)
793 public List
<Media
> listMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
794 Boolean limitToGalleries
, Boolean includeTaxonDescriptions
, Boolean includeOccurrences
,
795 Boolean includeTaxonNameDescriptions
, List
<String
> propertyPath
) {
797 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
798 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
800 if (limitToGalleries
== null) {
801 limitToGalleries
= false;
804 // --- resolve related taxa
805 if (includeRelationships
!= null) {
806 taxa
= listRelatedTaxa(taxon
, includeRelationships
, null, null, null, null);
809 taxa
.add((Taxon
) dao
.load(taxon
.getUuid()));
811 if(includeTaxonDescriptions
!= null && includeTaxonDescriptions
){
812 List
<TaxonDescription
> taxonDescriptions
= new ArrayList
<TaxonDescription
>();
813 // --- TaxonDescriptions
814 for (Taxon t
: taxa
) {
815 taxonDescriptions
.addAll(descriptionService
.listTaxonDescriptions(t
, null, null, null, null, propertyPath
));
817 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
818 if (!limitToGalleries
|| taxonDescription
.isImageGallery()) {
819 for (DescriptionElementBase element
: taxonDescription
.getElements()) {
820 for (Media media
: element
.getMedia()) {
821 taxonMedia
.add(media
);
828 if(includeOccurrences
!= null && includeOccurrences
) {
829 Set
<SpecimenOrObservationBase
> specimensOrObservations
= new HashSet
<SpecimenOrObservationBase
>();
831 for (Taxon t
: taxa
) {
832 specimensOrObservations
.addAll(occurrenceDao
.listByAssociatedTaxon(null, t
, null, null, null, null));
834 for (SpecimenOrObservationBase occurrence
: specimensOrObservations
) {
836 // direct media removed from specimen #3597
837 // taxonMedia.addAll(occurrence.getMedia());
839 // SpecimenDescriptions
840 Set
<SpecimenDescription
> specimenDescriptions
= occurrence
.getSpecimenDescriptions();
841 for (DescriptionBase specimenDescription
: specimenDescriptions
) {
842 if (!limitToGalleries
|| specimenDescription
.isImageGallery()) {
843 Set
<DescriptionElementBase
> elements
= specimenDescription
.getElements();
844 for (DescriptionElementBase element
: elements
) {
845 for (Media media
: element
.getMedia()) {
846 taxonMedia
.add(media
);
853 //TODO why may collections have media attached? #
854 if (occurrence
.isInstanceOf(DerivedUnit
.class)) {
855 DerivedUnit derivedUnit
= CdmBase
.deproxy(occurrence
, DerivedUnit
.class);
856 if (derivedUnit
.getCollection() != null){
857 taxonMedia
.addAll(derivedUnit
.getCollection().getMedia());
861 // pherograms & gelPhotos
862 if (occurrence
.isInstanceOf(DnaSample
.class)) {
863 DnaSample dnaSample
= CdmBase
.deproxy(occurrence
, DnaSample
.class);
864 Set
<Sequence
> sequences
= dnaSample
.getSequences();
865 //we do show only those gelPhotos which lead to a consensus sequence
866 for (Sequence sequence
: sequences
) {
867 Set
<Media
> dnaRelatedMedia
= new HashSet
<Media
>();
868 for (SingleRead singleRead
: sequence
.getSingleReads()){
869 Amplification amplification
= singleRead
.getAmplification();
870 dnaRelatedMedia
.add(amplification
.getGelPhoto());
871 dnaRelatedMedia
.add(singleRead
.getPherogram());
872 dnaRelatedMedia
.remove(null);
874 taxonMedia
.addAll(dnaRelatedMedia
);
881 if(includeTaxonNameDescriptions
!= null && includeTaxonNameDescriptions
) {
882 // --- TaxonNameDescription
883 Set
<TaxonNameDescription
> nameDescriptions
= new HashSet
<TaxonNameDescription
>();
884 for (Taxon t
: taxa
) {
885 nameDescriptions
.addAll(t
.getName().getDescriptions());
887 for(TaxonNameDescription nameDescription
: nameDescriptions
){
888 if (!limitToGalleries
|| nameDescription
.isImageGallery()) {
889 Set
<DescriptionElementBase
> elements
= nameDescription
.getElements();
890 for (DescriptionElementBase element
: elements
) {
891 for (Media media
: element
.getMedia()) {
892 taxonMedia
.add(media
);
899 beanInitializer
.initializeAll(taxonMedia
, propertyPath
);
904 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
907 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
908 return this.dao
.listByIds(listOfIDs
, null, null, null, null);
912 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
915 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
916 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
920 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
923 public int countAllRelationships() {
924 return this.dao
.countAllRelationships();
931 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
934 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
935 return this.dao
.findIdenticalTaxonNames(propertyPath
);
940 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
943 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
) throws ReferencedObjectUndeletableException
{
945 config
= new TaxonDeletionConfigurator();
949 if (! config
.isDeleteTaxonNodes()){
950 if (taxon
.getTaxonNodes().size() > 0){
951 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
952 throw new ReferencedObjectUndeletableException(message
);
957 // SynonymRelationShip
958 if (config
.isDeleteSynonymRelations()){
959 boolean removeSynonymNameFromHomotypicalGroup
= false;
960 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
961 Synonym synonym
= synRel
.getSynonym();
962 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
963 if (config
.isDeleteSynonymsIfPossible()){
965 boolean newHomotypicGroupIfNeeded
= true;
966 deleteSynonym(synonym
, taxon
, config
.isDeleteNameIfPossible(), newHomotypicGroupIfNeeded
);
968 deleteSynonymRelationships(synonym
, taxon
);
974 if (! config
.isDeleteTaxonRelationships()){
975 if (taxon
.getTaxonRelations().size() > 0){
976 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.";
977 throw new ReferencedObjectUndeletableException(message
);
983 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
985 for (TaxonDescription desc
: descriptions
){
986 if (config
.isDeleteDescriptions()){
987 //TODO use description delete configurator ?
988 //FIXME check if description is ALWAYS deletable
989 descriptionService
.delete(desc
);
991 if (desc
.getDescribedSpecimenOrObservation() != null){
992 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
993 " which also describes specimens or abservations";
994 throw new ReferencedObjectUndeletableException(message
);
1000 //check references with only reverse mapping
1001 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
1002 for (CdmBase referencingObject
: referencingObjects
){
1003 //IIdentificationKeys (Media, Polytomous, MultiAccess)
1004 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
1005 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
1006 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnit
.class).getTitleCache());
1007 throw new ReferencedObjectUndeletableException(message
);
1012 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
1013 String message
= "Taxon can't be deleted as it is used in polytomous key node";
1014 throw new ReferencedObjectUndeletableException(message
);
1018 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
1019 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
1020 throw new ReferencedObjectUndeletableException(message
);
1026 if (config
.isDeleteNameIfPossible()){
1028 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
1029 } catch (ReferencedObjectUndeletableException e
) {
1031 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
1038 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1040 @Transactional(readOnly
= false)
1042 public void deleteSynonym(Synonym synonym
, Taxon taxon
, boolean removeNameIfPossible
,boolean newHomotypicGroupIfNeeded
) {
1043 if (synonym
== null){
1046 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
1048 //remove synonymRelationship
1049 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
1051 taxonSet
.add(taxon
);
1053 taxonSet
.addAll(synonym
.getAcceptedTaxa());
1055 for (Taxon relatedTaxon
: taxonSet
){
1056 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
1057 relatedTaxon
.removeSynonym(synonym
, newHomotypicGroupIfNeeded
);
1059 this.saveOrUpdate(synonym
);
1061 //TODO remove name from homotypical group?
1063 //remove synonym (if necessary)
1064 if (synonym
.getSynonymRelations().isEmpty()){
1065 TaxonNameBase
<?
,?
> name
= synonym
.getName();
1066 synonym
.setName(null);
1067 dao
.delete(synonym
);
1069 //remove name if possible (and required)
1070 if (name
!= null && removeNameIfPossible
){
1072 nameService
.delete(name
, new NameDeletionConfigurator());
1073 }catch (DataChangeNoRollbackException ex
){
1074 if (logger
.isDebugEnabled()) {
1075 logger
.debug("Name wasn't deleted as it is referenced");
1084 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
1087 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
1089 return this.dao
.findIdenticalNamesNew(propertyPath
);
1093 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1096 public String
getPhylumName(TaxonNameBase name
){
1097 return this.dao
.getPhylumName(name
);
1101 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
1104 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
1105 return dao
.deleteSynonymRelationships(syn
, taxon
);
1109 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
1112 public long deleteSynonymRelationships(Synonym syn
) {
1113 return dao
.deleteSynonymRelationships(syn
, null);
1118 * @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)
1121 public List
<SynonymRelationship
> listSynonymRelationships(
1122 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
1123 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
1124 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
1126 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
1127 if(numberOfResults
> 0) { // no point checking again
1128 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
1134 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
1137 public Taxon
findBestMatchingTaxon(String taxonName
) {
1138 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
1139 config
.setTaxonNameTitle(taxonName
);
1140 return findBestMatchingTaxon(config
);
1146 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
1148 Taxon bestCandidate
= null;
1150 // 1. search for acceptet taxa
1151 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1152 boolean bestCandidateMatchesSecUuid
= false;
1153 boolean bestCandidateIsInClassification
= false;
1154 int countEqualCandidates
= 0;
1155 for(TaxonBase taxonBaseCandidate
: taxonList
){
1156 if(taxonBaseCandidate
instanceof Taxon
){
1157 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
1158 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
1159 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
1161 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
1162 bestCandidate
= newCanditate
;
1163 countEqualCandidates
= 1;
1164 bestCandidateMatchesSecUuid
= true;
1168 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
1169 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
1171 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
1172 bestCandidate
= newCanditate
;
1173 countEqualCandidates
= 1;
1174 bestCandidateIsInClassification
= true;
1177 if (bestCandidate
== null){
1178 bestCandidate
= newCanditate
;
1179 countEqualCandidates
= 1;
1183 }else{ //not Taxon.class
1186 countEqualCandidates
++;
1189 if (bestCandidate
!= null){
1190 if(countEqualCandidates
> 1){
1191 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
1192 return bestCandidate
;
1194 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
1195 return bestCandidate
;
1200 // 2. search for synonyms
1201 if (config
.isIncludeSynonyms()){
1202 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1203 for(TaxonBase taxonBase
: synonymList
){
1204 if(taxonBase
instanceof Synonym
){
1205 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
1206 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
1207 if(!acceptetdCandidates
.isEmpty()){
1208 bestCandidate
= acceptetdCandidates
.iterator().next();
1209 if(acceptetdCandidates
.size() == 1){
1210 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
1211 return bestCandidate
;
1213 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
1214 return bestCandidate
;
1216 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
1222 } catch (Exception e
){
1224 e
.printStackTrace();
1227 return bestCandidate
;
1230 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
1231 UUID configClassificationUuid
= config
.getClassificationUuid();
1232 if (configClassificationUuid
== null){
1235 for (TaxonNode node
: taxon
.getTaxonNodes()){
1236 UUID classUuid
= node
.getClassification().getUuid();
1237 if (configClassificationUuid
.equals(classUuid
)){
1244 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1245 UUID configSecUuid
= config
.getSecUuid();
1246 if (configSecUuid
== null){
1249 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1250 return configSecUuid
.equals(taxonSecUuid
);
1254 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1257 public Synonym
findBestMatchingSynonym(String taxonName
) {
1258 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1259 if(! synonymList
.isEmpty()){
1260 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1261 if(synonymList
.size() == 1){
1262 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1265 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1274 * @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)
1277 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1278 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1280 Synonym synonym
= oldSynonymRelation
.getSynonym();
1281 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1282 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1283 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1284 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1285 //set default relationship type
1286 if (newSynonymRelationshipType
== null){
1287 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1289 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1291 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1292 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1293 boolean isSingleInGroup
= !(hgSize
> 1);
1295 if (! isSingleInGroup
){
1296 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1297 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1298 if (isHomotypicToAccepted
){
1299 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.";
1300 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1301 message
= String
.format(message
, homotypicRelatives
);
1302 throw new HomotypicalGroupChangeException(message
);
1304 if (! moveHomotypicGroup
){
1305 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.";
1306 throw new HomotypicalGroupChangeException(message
);
1309 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1311 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1313 SynonymRelationship result
= null;
1314 //move all synonyms to new taxon
1315 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1316 for (Synonym syn
: homotypicSynonyms
){
1317 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1318 for (SynonymRelationship synRelation
: synRelations
){
1319 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1320 Reference
<?
> newReference
= reference
;
1321 if (newReference
== null && keepReference
){
1322 newReference
= synRelation
.getCitation();
1324 String newRefDetail
= referenceDetail
;
1325 if (newRefDetail
== null && keepReference
){
1326 newRefDetail
= synRelation
.getCitationMicroReference();
1328 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1329 fromTaxon
.removeSynonymRelation(synRelation
, false);
1331 //change homotypic group of synonym if relType is 'homotypic'
1332 // if (newRelTypeIsHomotypic){
1333 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1336 if (synRelation
.equals(oldSynonymRelation
)){
1337 result
= newSynRelation
;
1343 saveOrUpdate(newTaxon
);
1344 //Assert that there is a result
1345 if (result
== null){
1346 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1347 throw new IllegalStateException(message
);
1353 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1356 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1357 return dao
.getUuidAndTitleCacheTaxon();
1361 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1364 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1365 return dao
.getUuidAndTitleCacheSynonym();
1369 * @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)
1372 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1373 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1374 Classification classification
, List
<Language
> languages
,
1375 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1378 LuceneSearch luceneSearch
= prepareFindByFullTextSearch(clazz
, queryString
, classification
, languages
, highlightFragments
);
1380 // --- execute search
1381 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1383 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1384 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1386 // --- initialize taxa, thighlight matches ....
1387 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1388 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1389 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1391 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1392 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1396 public Pager
<SearchResult
<TaxonBase
>> findByDistribution(List
<NamedArea
> areaFilter
, List
<PresenceAbsenceTermBase
<?
>> statusFilter
,
1397 Classification classification
,
1398 Integer pageSize
, Integer pageNumber
,
1399 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws IOException
, ParseException
{
1401 LuceneSearch luceneSearch
= prepareByDistributionSearch(areaFilter
, statusFilter
, classification
);
1403 // --- execute search
1404 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1406 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1407 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1409 // --- initialize taxa, thighlight matches ....
1410 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1411 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1412 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1414 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1415 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1420 * @param queryString
1421 * @param classification
1423 * @param highlightFragments
1424 * @param directorySelectClass
1427 protected LuceneSearch
prepareFindByFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Language
> languages
,
1428 boolean highlightFragments
) {
1429 BooleanQuery finalQuery
= new BooleanQuery();
1430 BooleanQuery textQuery
= new BooleanQuery();
1432 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, TaxonBase
.class);
1433 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1435 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1436 luceneSearch
.setSortFields(sortFields
);
1438 // ---- search criteria
1439 luceneSearch
.setCdmTypRestriction(clazz
);
1441 textQuery
.add(taxonBaseQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1442 textQuery
.add(taxonBaseQueryFactory
.newDefinedTermQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1444 finalQuery
.add(textQuery
, Occur
.MUST
);
1446 if(classification
!= null){
1447 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1449 luceneSearch
.setQuery(finalQuery
);
1451 if(highlightFragments
){
1452 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1454 return luceneSearch
;
1458 * Uses org.apache.lucene.search.join.JoinUtil for query time joining, alternatively
1459 * the BlockJoinQuery could be used. The latter might be more memory save but has the
1460 * drawback of requiring to do the join an indexing time.
1461 * see http://dev.e-taxonomy.eu/trac/wiki/LuceneNotes#JoinsinLucene for more information on this.
1463 * Joins TaxonRelationShip with Taxon depending on the direction of the given edge:
1465 * <li>direct, everted: {@link Direction.relatedTo}: TaxonRelationShip.relatedTo.id --> Taxon.id </li>
1466 * <li>inverse: {@link Direction.relatedFrom}: TaxonRelationShip.relatedFrom.id --> Taxon.id </li>
1469 * @param queryString
1470 * @param classification
1472 * @param highlightFragments
1474 * @throws IOException
1476 protected LuceneSearch
prepareFindByTaxonRelationFullTextSearch(TaxonRelationshipEdge edge
, String queryString
, Classification classification
, List
<Language
> languages
,
1477 boolean highlightFragments
) throws IOException
{
1480 String queryTermField
;
1481 String toField
= "id"; // TaxonBase.uuid
1483 if(edge
.isBidirectional()){
1484 throw new RuntimeException("Bidirectional joining not supported!");
1487 fromField
= "relatedFrom.id";
1488 queryTermField
= "relatedFrom.titleCache";
1489 } else if(edge
.isInvers()) {
1490 fromField
= "relatedTo.id";
1491 queryTermField
= "relatedTo.titleCache";
1493 throw new RuntimeException("Invalid direction: " + edge
.getDirections());
1496 BooleanQuery finalQuery
= new BooleanQuery();
1498 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonBase
.class);
1499 QueryFactory taxonBaseQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonBase
.class);
1501 BooleanQuery joinFromQuery
= new BooleanQuery();
1502 joinFromQuery
.add(taxonBaseQueryFactory
.newTermQuery(queryTermField
, queryString
), Occur
.MUST
);
1503 joinFromQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("type.id", edge
.getTaxonRelationshipType()), Occur
.MUST
);
1504 Query joinQuery
= taxonBaseQueryFactory
.newJoinQuery(fromField
, toField
, joinFromQuery
, TaxonRelationship
.class);
1506 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1507 luceneSearch
.setSortFields(sortFields
);
1509 finalQuery
.add(joinQuery
, Occur
.MUST
);
1511 if(classification
!= null){
1512 finalQuery
.add(taxonBaseQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1514 luceneSearch
.setQuery(finalQuery
);
1516 if(highlightFragments
){
1517 luceneSearch
.setHighlightFields(taxonBaseQueryFactory
.getTextFieldNamesAsArray());
1519 return luceneSearch
;
1526 * @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)
1529 public Pager
<SearchResult
<TaxonBase
>> findTaxaAndNamesByFullText(
1530 EnumSet
<TaxaAndNamesSearchMode
> searchModes
, String queryString
, Classification classification
,
1531 Set
<NamedArea
> namedAreas
, Set
<PresenceAbsenceTermBase
<?
>> distributionStatus
, List
<Language
> languages
,
1532 boolean highlightFragments
, Integer pageSize
,
1533 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
)
1534 throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
1536 if(highlightFragments
){
1537 logger
.warn("findTaxaAndNamesByFullText() : fragment highlighting is " +
1538 "currently not fully supported by this method and thus " +
1539 "may not work with common names and misapplied names.");
1542 // convert sets to lists
1543 List
<NamedArea
> namedAreaList
= null;
1544 List
<PresenceAbsenceTermBase
<?
>>distributionStatusList
= null;
1545 if(namedAreas
!= null){
1546 namedAreaList
= new ArrayList
<NamedArea
>(namedAreas
.size());
1547 namedAreaList
.addAll(namedAreas
);
1549 if(distributionStatus
!= null){
1550 distributionStatusList
= new ArrayList
<PresenceAbsenceTermBase
<?
>>(distributionStatus
.size());
1551 distributionStatusList
.addAll(distributionStatus
);
1554 // set default if parameter is null
1555 if(searchModes
== null){
1556 searchModes
= EnumSet
.of(TaxaAndNamesSearchMode
.doTaxa
);
1559 boolean addDistributionFilter
= namedAreas
!= null && namedAreas
.size() > 0;
1561 List
<LuceneSearch
> luceneSearches
= new ArrayList
<LuceneSearch
>();
1562 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1565 ======== filtering by distribution , HOWTO ========
1567 - http://www.javaranch.com/journal/2009/02/filtering-a-lucene-search.html
1568 - http://stackoverflow.com/questions/17709256/lucene-solr-using-complex-filters -> QueryWrapperFilter
1569 add Filter to search as http://lucene.apache.org/core/3_6_0/api/all/org/apache/lucene/search/Filter.html
1570 which will be put into a FilteredQuersy in the end ?
1573 3. how does it work in spatial?
1575 - http://www.nsshutdown.com/projects/lucene/whitepaper/locallucene_v2.html
1576 - http://www.infoq.com/articles/LuceneSpatialSupport
1577 - http://www.mhaller.de/archives/156-Spatial-search-with-Lucene.html
1578 ------------------------------------------------------------------------
1581 A) use a separate distribution filter per index sub-query/search:
1582 - byTaxonSyonym (query TaxaonBase):
1583 use a join area filter (Distribution -> TaxonBase)
1584 - byCommonName (query DescriptionElementBase): use an area filter on
1585 DescriptionElementBase !!! PROBLEM !!!
1586 This cannot work since the distributions are different entities than the
1587 common names and thus these are different lucene documents.
1588 - byMisaplliedNames (join query TaxonRelationship -> TaxaonBase):
1589 use a join area filter (Distribution -> TaxonBase)
1591 B) use a common distribution filter for all index sub-query/searches:
1592 - use a common join area filter (Distribution -> TaxonBase)
1593 - also implement the byCommonName as join query (CommonName -> TaxonBase)
1594 PROBLEM in this case: we are losing the fragment highlighting for the
1595 common names, since the returned documents are always TaxonBases
1598 /* The QueryFactory for creating filter queries on Distributions should
1599 * The query factory used for the common names query cannot be reused
1600 * for this case, since we want to only record the text fields which are
1601 * actually used in the primary query
1603 QueryFactory distributionFilterQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Distribution
.class);
1605 BooleanFilter multiIndexByAreaFilter
= new BooleanFilter();
1608 // search for taxa or synonyms
1609 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) || searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1610 Class taxonBaseSubclass
= TaxonBase
.class;
1611 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && !searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1612 taxonBaseSubclass
= Taxon
.class;
1613 } else if (!searchModes
.contains(TaxaAndNamesSearchMode
.doTaxa
) && searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)) {
1614 taxonBaseSubclass
= Synonym
.class;
1616 luceneSearches
.add(prepareFindByFullTextSearch(taxonBaseSubclass
, queryString
, classification
, languages
, highlightFragments
));
1617 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1618 /* A) does not work!!!!
1619 if(addDistributionFilter){
1620 // in this case we need a filter which uses a join query
1621 // to get the TaxonBase documents for the DescriptionElementBase documents
1622 // which are matching the areas in question
1623 Query taxonAreaJoinQuery = createByDistributionJoinQuery(
1625 distributionStatusList,
1626 distributionFilterQueryFactory
1628 multiIndexByAreaFilter.add(new QueryWrapperFilter(taxonAreaJoinQuery), Occur.SHOULD);
1631 if(addDistributionFilter
&& searchModes
.contains(TaxaAndNamesSearchMode
.doSynonyms
)){
1632 // add additional area filter for synonyms
1633 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
1634 String toField
= "accTaxon.id"; // id in TaxonBase index
1636 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, distributionFilterQueryFactory
);
1638 Query taxonAreaJoinQuery
= distributionFilterQueryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
1639 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
1644 // search by CommonTaxonName
1645 if(searchModes
.contains(TaxaAndNamesSearchMode
.doTaxaByCommonNames
)) {
1647 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
1648 Query byCommonNameJoinQuery
= descriptionElementQueryFactory
.newJoinQuery(
1649 "inDescription.taxon.id",
1651 createByDescriptionElementFullTextQuery(queryString
, classification
, null, languages
, descriptionElementQueryFactory
),
1652 CommonTaxonName
.class);
1653 logger
.debug("byCommonNameJoinQuery: " + byCommonNameJoinQuery
.toString());
1654 LuceneSearch byCommonNameSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
1655 byCommonNameSearch
.setCdmTypRestriction(Taxon
.class);
1656 byCommonNameSearch
.setQuery(byCommonNameJoinQuery
);
1657 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1659 luceneSearches
.add(byCommonNameSearch
);
1661 /* A) does not work!!!!
1663 prepareByDescriptionElementFullTextSearch(CommonTaxonName.class,
1664 queryString, classification, null, languages, highlightFragments)
1666 idFieldMap.put(CdmBaseType.DESCRIPTION_ELEMENT, "inDescription.taxon.id");
1667 if(addDistributionFilter){
1668 // in this case we are able to use DescriptionElementBase documents
1669 // which are matching the areas in question directly
1670 BooleanQuery byDistributionQuery = createByDistributionQuery(
1672 distributionStatusList,
1673 distributionFilterQueryFactory
1675 multiIndexByAreaFilter.add(new QueryWrapperFilter(byDistributionQuery), Occur.SHOULD);
1679 // search by misapplied names
1680 if(searchModes
.contains(TaxaAndNamesSearchMode
.doMisappliedNames
)) {
1682 // prepareFindByTaxonRelationFullTextSearch() is making use of JoinUtil.createJoinQuery()
1683 // which allows doing query time joins
1684 // finds the misapplied name (Taxon B) which is an misapplication for
1685 // a related Taxon A.
1687 luceneSearches
.add(prepareFindByTaxonRelationFullTextSearch(
1688 new TaxonRelationshipEdge(TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), Direction
.relatedTo
),
1689 queryString
, classification
, languages
, highlightFragments
));
1690 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1692 if(addDistributionFilter
){
1693 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
1696 * Here i was facing wired and nasty bug which took me bugging be really for hours until I found this solution.
1697 * Maybe this is a but in java itself java.
1699 * When the string toField is constructed by using the expression TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString()
1702 * String toField = "relation." + TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString() +".to.id";
1704 * The byDistributionQuery fails, however when the uuid is first stored in another string variable the query
1705 * will execute as expected:
1707 * String misappliedNameForUuid = TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString();
1708 * String toField = "relation." + misappliedNameForUuid +".to.id";
1710 * Comparing both strings by the String.equals method returns true, so both String are identical.
1712 * The bug occurs when running eu.etaxonomy.cdm.api.service.TaxonServiceSearchTest in eclipse and in maven and seems to to be
1713 * dependent from a specific jvm (openjdk6 6b27-1.12.6-1ubuntu0.13.04.2, openjdk7 7u25-2.3.10-1ubuntu0.13.04.2, oracle jdk1.7.0_25 tested)
1714 * The bug is persistent after a reboot of the development computer.
1716 // String misappliedNameForUuid = TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString();
1717 // String toField = "relation." + misappliedNameForUuid +".to.id";
1718 String toField
= "relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id";
1719 // System.out.println("relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id".equals("relation." + misappliedNameForUuid +".to.id") ? " > identical" : " > different");
1720 // System.out.println("relation.1ed87175-59dd-437e-959e-0d71583d8417.to.id".equals("relation." + TaxonRelationshipType.MISAPPLIED_NAME_FOR().getUuid().toString() +".to.id") ? " > identical" : " > different");
1722 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, distributionFilterQueryFactory
);
1723 Query taxonAreaJoinQuery
= distributionFilterQueryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
1724 QueryWrapperFilter filter
= new QueryWrapperFilter(taxonAreaJoinQuery
);
1726 // debug code for bug described above
1727 DocIdSet filterMatchSet
= filter
.getDocIdSet(luceneIndexToolProvider
.getIndexReaderFor(Taxon
.class));
1728 System
.err
.println(DocIdBitSetPrinter
.docsAsString(filterMatchSet
, 100));
1730 multiIndexByAreaFilter
.add(filter
, Occur
.SHOULD
);
1734 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
,
1735 luceneSearches
.toArray(new LuceneSearch
[luceneSearches
.size()]));
1738 if(addDistributionFilter
){
1741 // in this case we need a filter which uses a join query
1742 // to get the TaxonBase documents for the DescriptionElementBase documents
1743 // which are matching the areas in question
1745 // for toTaxa, doByCommonName
1746 Query taxonAreaJoinQuery
= createByDistributionJoinQuery(
1748 distributionStatusList
,
1749 distributionFilterQueryFactory
1751 multiIndexByAreaFilter
.add(new QueryWrapperFilter(taxonAreaJoinQuery
), Occur
.SHOULD
);
1754 if (addDistributionFilter
){
1755 multiSearch
.setFilter(multiIndexByAreaFilter
);
1757 // --- execute search
1758 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1760 // --- initialize taxa, highlight matches ....
1761 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1764 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1765 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1767 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1768 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1772 * @param namedAreaList at least one area must be in the list
1773 * @param distributionStatusList optional
1775 * @throws IOException
1777 protected Query
createByDistributionJoinQuery(
1778 List
<NamedArea
> namedAreaList
,
1779 List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
,
1780 QueryFactory queryFactory
1781 ) throws IOException
{
1783 String fromField
= "inDescription.taxon.id"; // in DescriptionElementBase index
1784 String toField
= "id"; // id in TaxonBase index
1786 BooleanQuery byDistributionQuery
= createByDistributionQuery(namedAreaList
, distributionStatusList
, queryFactory
);
1788 Query taxonAreaJoinQuery
= queryFactory
.newJoinQuery(fromField
, toField
, byDistributionQuery
, Distribution
.class);
1790 return taxonAreaJoinQuery
;
1794 * @param namedAreaList
1795 * @param distributionStatusList
1796 * @param queryFactory
1799 private BooleanQuery
createByDistributionQuery(List
<NamedArea
> namedAreaList
,
1800 List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
, QueryFactory queryFactory
) {
1801 BooleanQuery areaQuery
= new BooleanQuery();
1802 // area field from Distribution
1803 areaQuery
.add(queryFactory
.newEntityIdsQuery("area.id", namedAreaList
), Occur
.MUST
);
1805 // status field from Distribution
1806 if(distributionStatusList
!= null && distributionStatusList
.size() > 0){
1807 areaQuery
.add(queryFactory
.newEntityIdsQuery("status.id", distributionStatusList
), Occur
.MUST
);
1810 logger
.debug("createByDistributionQuery() query: " + areaQuery
.toString());
1815 * This method has been primarily created for testing the area join query but might
1816 * also be useful in other situations
1818 * @param namedAreaList
1819 * @param distributionStatusList
1820 * @param classification
1821 * @param highlightFragments
1823 * @throws IOException
1825 protected LuceneSearch
prepareByDistributionSearch(
1826 List
<NamedArea
> namedAreaList
, List
<PresenceAbsenceTermBase
<?
>> distributionStatusList
,
1827 Classification classification
) throws IOException
{
1829 BooleanQuery finalQuery
= new BooleanQuery();
1831 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, Taxon
.class);
1833 // FIXME is this query factory using the wrong type?
1834 QueryFactory taxonQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(Taxon
.class);
1836 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1837 luceneSearch
.setSortFields(sortFields
);
1840 Query byAreaQuery
= createByDistributionJoinQuery(namedAreaList
, distributionStatusList
, taxonQueryFactory
);
1842 finalQuery
.add(byAreaQuery
, Occur
.MUST
);
1844 if(classification
!= null){
1845 finalQuery
.add(taxonQueryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1848 logger
.info("prepareByAreaSearch() query: " + finalQuery
.toString());
1849 luceneSearch
.setQuery(finalQuery
);
1851 return luceneSearch
;
1857 * @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)
1860 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1861 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1862 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1863 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1866 LuceneSearch luceneSearch
= prepareByDescriptionElementFullTextSearch(clazz
, queryString
, classification
, features
, languages
, highlightFragments
);
1868 // --- execute search
1869 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1871 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1872 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1874 // --- initialize taxa, highlight matches ....
1875 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1876 @SuppressWarnings("rawtypes")
1877 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1878 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1880 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1881 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1887 public Pager
<SearchResult
<TaxonBase
>> findByEverythingFullText(String queryString
,
1888 Classification classification
, List
<Language
> languages
, boolean highlightFragments
,
1889 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
, LuceneMultiSearchException
{
1891 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, null, languages
, highlightFragments
);
1892 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
);
1894 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneIndexToolProvider
, luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
1896 // --- execute search
1897 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1899 // --- initialize taxa, highlight matches ....
1900 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1902 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1903 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1904 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1906 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1907 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1909 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1910 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1917 * @param queryString
1918 * @param classification
1921 * @param highlightFragments
1922 * @param directorySelectClass
1925 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
,
1926 String queryString
, Classification classification
, List
<Feature
> features
,
1927 List
<Language
> languages
, boolean highlightFragments
) {
1929 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, DescriptionElementBase
.class);
1930 QueryFactory descriptionElementQueryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(DescriptionElementBase
.class);
1932 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", SortField
.STRING
, false)};
1934 BooleanQuery finalQuery
= createByDescriptionElementFullTextQuery(queryString
, classification
, features
,
1935 languages
, descriptionElementQueryFactory
);
1937 luceneSearch
.setSortFields(sortFields
);
1938 luceneSearch
.setCdmTypRestriction(clazz
);
1939 luceneSearch
.setQuery(finalQuery
);
1940 if(highlightFragments
){
1941 luceneSearch
.setHighlightFields(descriptionElementQueryFactory
.getTextFieldNamesAsArray());
1944 return luceneSearch
;
1948 * @param queryString
1949 * @param classification
1952 * @param descriptionElementQueryFactory
1955 private BooleanQuery
createByDescriptionElementFullTextQuery(String queryString
, Classification classification
,
1956 List
<Feature
> features
, List
<Language
> languages
, QueryFactory descriptionElementQueryFactory
) {
1957 BooleanQuery finalQuery
= new BooleanQuery();
1958 BooleanQuery textQuery
= new BooleanQuery();
1959 textQuery
.add(descriptionElementQueryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1963 if(languages
== null || languages
.size() == 0){
1964 nameQuery
= descriptionElementQueryFactory
.newTermQuery("name", queryString
);
1966 nameQuery
= new BooleanQuery();
1967 BooleanQuery languageSubQuery
= new BooleanQuery();
1968 for(Language lang
: languages
){
1969 languageSubQuery
.add(descriptionElementQueryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString(), false), Occur
.SHOULD
);
1971 ((BooleanQuery
) nameQuery
).add(descriptionElementQueryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
1972 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1974 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1977 // text field from TextData
1978 textQuery
.add(descriptionElementQueryFactory
.newMultilanguageTextQuery("text", queryString
, languages
), Occur
.SHOULD
);
1980 // --- TermBase fields - by representation ----
1981 // state field from CategoricalData
1982 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("stateData.state", queryString
, languages
), Occur
.SHOULD
);
1984 // state field from CategoricalData
1985 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("stateData.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1987 // area field from Distribution
1988 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("area", queryString
, languages
), Occur
.SHOULD
);
1990 // status field from Distribution
1991 textQuery
.add(descriptionElementQueryFactory
.newDefinedTermQuery("status", queryString
, languages
), Occur
.SHOULD
);
1993 finalQuery
.add(textQuery
, Occur
.MUST
);
1994 // --- classification ----
1996 if(classification
!= null){
1997 finalQuery
.add(descriptionElementQueryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
2000 // --- IdentifieableEntity fields - by uuid
2001 if(features
!= null && features
.size() > 0 ){
2002 finalQuery
.add(descriptionElementQueryFactory
.newEntityUuidsQuery("feature.uuid", features
), Occur
.MUST
);
2005 // the description must be associated with a taxon
2006 finalQuery
.add(descriptionElementQueryFactory
.newIsNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
2008 logger
.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery
.toString());
2013 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
2014 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
2015 * This method is a convenient means to retrieve a Lucene query string for such the fields.
2017 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
2018 * or {@link MultilanguageTextFieldBridge }
2019 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
2020 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
2021 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
2023 * TODO move to utiliy class !!!!!!!!
2025 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
2027 if(stringBuilder
== null){
2028 stringBuilder
= new StringBuilder();
2030 if(languages
== null || languages
.size() == 0){
2031 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
2033 for(Language lang
: languages
){
2034 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
2037 return stringBuilder
;
2041 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
2042 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2043 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
2045 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
2048 UUID nameUuid
= taxon
.getName().getUuid();
2049 ZoologicalName taxonName
= getZoologicalName(nameUuid
, zooHashMap
);
2050 String epithetOfTaxon
= null;
2051 String infragenericEpithetOfTaxon
= null;
2052 String infraspecificEpithetOfTaxon
= null;
2053 if (taxonName
.isSpecies()){
2054 epithetOfTaxon
= taxonName
.getSpecificEpithet();
2055 } else if (taxonName
.isInfraGeneric()){
2056 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
2057 } else if (taxonName
.isInfraSpecific()){
2058 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
2060 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
2061 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
2062 List
<String
> taxonNames
= new ArrayList
<String
>();
2064 for (TaxonNode node
: nodes
){
2065 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
2066 // List<String> synonymsEpithet = new ArrayList<String>();
2068 if (node
.getClassification().equals(classification
)){
2069 if (!node
.isTopmostNode()){
2070 TaxonNode parent
= node
.getParent();
2071 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
2072 TaxonNameBase
<?
,?
> parentName
= parent
.getTaxon().getName();
2073 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
2074 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
2075 Rank rankOfTaxon
= taxonName
.getRank();
2078 //create inferred synonyms for species, subspecies
2079 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
2081 Synonym inferredEpithet
= null;
2082 Synonym inferredGenus
= null;
2083 Synonym potentialCombination
= null;
2085 List
<String
> propertyPaths
= new ArrayList
<String
>();
2086 propertyPaths
.add("synonym");
2087 propertyPaths
.add("synonym.name");
2088 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
2089 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
2091 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2092 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
2094 List
<TaxonRelationship
> taxonRelListParent
= null;
2095 List
<TaxonRelationship
> taxonRelListTaxon
= null;
2096 if (doWithMisappliedNames
){
2097 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2098 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
2102 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
2105 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2106 Synonym syn
= synonymRelationOfParent
.getSynonym();
2108 inferredEpithet
= createInferredEpithets(taxon
,
2109 zooHashMap
, taxonName
, epithetOfTaxon
,
2110 infragenericEpithetOfTaxon
,
2111 infraspecificEpithetOfTaxon
,
2112 taxonNames
, parentName
,
2116 inferredSynonyms
.add(inferredEpithet
);
2117 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2118 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2121 if (doWithMisappliedNames
){
2123 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
2124 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2126 inferredEpithet
= createInferredEpithets(taxon
,
2127 zooHashMap
, taxonName
, epithetOfTaxon
,
2128 infragenericEpithetOfTaxon
,
2129 infraspecificEpithetOfTaxon
,
2130 taxonNames
, parentName
,
2133 inferredSynonyms
.add(inferredEpithet
);
2134 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
2135 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
2139 if (!taxonNames
.isEmpty()){
2140 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2141 ZoologicalName name
;
2142 if (!synNotInCDM
.isEmpty()){
2143 inferredSynonymsToBeRemoved
.clear();
2145 for (Synonym syn
:inferredSynonyms
){
2146 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2147 if (!synNotInCDM
.contains(name
.getNameCache())){
2148 inferredSynonymsToBeRemoved
.add(syn
);
2152 // Remove identified Synonyms from inferredSynonyms
2153 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2154 inferredSynonyms
.remove(synonym
);
2159 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
2162 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2163 TaxonNameBase synName
;
2164 ZoologicalName inferredSynName
;
2166 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2167 inferredGenus
= createInferredGenus(taxon
,
2168 zooHashMap
, taxonName
, epithetOfTaxon
,
2169 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
2171 inferredSynonyms
.add(inferredGenus
);
2172 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2173 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2178 if (doWithMisappliedNames
){
2180 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2181 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2182 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
2184 inferredSynonyms
.add(inferredGenus
);
2185 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
2186 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
2191 if (!taxonNames
.isEmpty()){
2192 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2193 ZoologicalName name
;
2194 if (!synNotInCDM
.isEmpty()){
2195 inferredSynonymsToBeRemoved
.clear();
2197 for (Synonym syn
:inferredSynonyms
){
2198 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2199 if (!synNotInCDM
.contains(name
.getNameCache())){
2200 inferredSynonymsToBeRemoved
.add(syn
);
2204 // Remove identified Synonyms from inferredSynonyms
2205 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2206 inferredSynonyms
.remove(synonym
);
2211 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
2213 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
2214 ZoologicalName inferredSynName
;
2215 //for all synonyms of the parent...
2216 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
2217 TaxonNameBase synName
;
2218 Synonym synParent
= synonymRelationOfParent
.getSynonym();
2219 synName
= synParent
.getName();
2221 HibernateProxyHelper
.deproxy(synParent
);
2223 // Set the sourceReference
2224 sourceReference
= synParent
.getSec();
2226 // Determine the idInSource
2227 String idInSourceParent
= getIdInSource(synParent
);
2229 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2230 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2231 String synParentInfragenericName
= null;
2232 String synParentSpecificEpithet
= null;
2234 if (parentSynZooName
.isInfraGeneric()){
2235 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2237 if (parentSynZooName
.isSpecies()){
2238 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2241 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2242 synonymsGenus.put(synGenusName, idInSource);
2245 //for all synonyms of the taxon
2247 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
2249 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
2250 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2251 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
2253 synParentInfragenericName
,
2254 synParentSpecificEpithet
, syn
, zooHashMap
);
2256 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2257 inferredSynonyms
.add(potentialCombination
);
2258 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2259 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2266 if (doWithMisappliedNames
){
2268 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
2270 TaxonNameBase misappliedParentName
;
2272 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
2273 misappliedParentName
= misappliedParent
.getName();
2275 HibernateProxyHelper
.deproxy(misappliedParent
);
2277 // Set the sourceReference
2278 sourceReference
= misappliedParent
.getSec();
2280 // Determine the idInSource
2281 String idInSourceParent
= getIdInSource(misappliedParent
);
2283 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
2284 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
2285 String synParentInfragenericName
= null;
2286 String synParentSpecificEpithet
= null;
2288 if (parentSynZooName
.isInfraGeneric()){
2289 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
2291 if (parentSynZooName
.isSpecies()){
2292 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
2296 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
2297 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
2298 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
2299 potentialCombination
= createPotentialCombination(
2300 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
2302 synParentInfragenericName
,
2303 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
2306 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
2307 inferredSynonyms
.add(potentialCombination
);
2308 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
2309 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
2314 if (!taxonNames
.isEmpty()){
2315 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
2316 ZoologicalName name
;
2317 if (!synNotInCDM
.isEmpty()){
2318 inferredSynonymsToBeRemoved
.clear();
2319 for (Synonym syn
:inferredSynonyms
){
2321 name
= (ZoologicalName
) syn
.getName();
2322 }catch (ClassCastException e
){
2323 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
2325 if (!synNotInCDM
.contains(name
.getNameCache())){
2326 inferredSynonymsToBeRemoved
.add(syn
);
2329 // Remove identified Synonyms from inferredSynonyms
2330 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
2331 inferredSynonyms
.remove(synonym
);
2337 logger
.info("The synonymrelationship type is not defined.");
2338 return inferredSynonyms
;
2345 return inferredSynonyms
;
2348 private Synonym
createPotentialCombination(String idInSourceParent
,
2349 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
2350 String synParentInfragenericName
, String synParentSpecificEpithet
,
2351 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2352 Synonym potentialCombination
;
2353 Reference sourceReference
;
2354 ZoologicalName inferredSynName
;
2355 HibernateProxyHelper
.deproxy(syn
);
2357 // Set sourceReference
2358 sourceReference
= syn
.getSec();
2359 if (sourceReference
== null){
2360 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2362 if (!parentSynZooName
.getTaxa().isEmpty()){
2363 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
2365 sourceReference
= taxon
.getSec();
2368 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
2370 String synTaxonInfraSpecificName
= null;
2372 if (parentSynZooName
.isSpecies()){
2373 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
2376 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
2377 synonymsEpithet.add(epithetName);
2380 //create potential combinations...
2381 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
2383 inferredSynName
.setGenusOrUninomial(synParentGenus
);
2384 if (zooSynName
.isSpecies()){
2385 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
2386 if (parentSynZooName
.isInfraGeneric()){
2387 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2390 if (zooSynName
.isInfraSpecific()){
2391 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
2392 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
2394 if (parentSynZooName
.isInfraGeneric()){
2395 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
2399 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
2401 // Set the sourceReference
2402 potentialCombination
.setSec(sourceReference
);
2405 // Determine the idInSource
2406 String idInSourceSyn
= getIdInSource(syn
);
2408 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
2409 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
, idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2410 inferredSynName
.addSource(originalSource
);
2411 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
, idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
2412 potentialCombination
.addSource(originalSource
);
2415 inferredSynName
.generateTitle();
2417 return potentialCombination
;
2420 private Synonym
createInferredGenus(Taxon taxon
,
2421 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2422 String epithetOfTaxon
, String genusOfTaxon
,
2423 List
<String
> taxonNames
, ZoologicalName zooParentName
,
2426 Synonym inferredGenus
;
2427 TaxonNameBase synName
;
2428 ZoologicalName inferredSynName
;
2429 synName
=syn
.getName();
2430 HibernateProxyHelper
.deproxy(syn
);
2432 // Determine the idInSource
2433 String idInSourceSyn
= getIdInSource(syn
);
2434 String idInSourceTaxon
= getIdInSource(taxon
);
2435 // Determine the sourceReference
2436 Reference sourceReference
= syn
.getSec();
2438 //logger.warn(sourceReference.getTitleCache());
2440 synName
= syn
.getName();
2441 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2442 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
2443 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
2444 synonymsEpithet.add(synSpeciesEpithetName);
2447 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2448 //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...
2451 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
2452 if (zooParentName
.isInfraGeneric()){
2453 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
2456 if (taxonName
.isSpecies()){
2457 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
2459 if (taxonName
.isInfraSpecific()){
2460 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2461 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
2465 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
2467 // Set the sourceReference
2468 inferredGenus
.setSec(sourceReference
);
2470 // Add the original source
2471 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
2472 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2473 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2474 inferredGenus
.addSource(originalSource
);
2476 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2477 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2478 inferredSynName
.addSource(originalSource
);
2479 originalSource
= null;
2482 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
2483 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2484 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2485 inferredGenus
.addSource(originalSource
);
2487 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2488 idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2489 inferredSynName
.addSource(originalSource
);
2490 originalSource
= null;
2493 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
2495 inferredSynName
.generateTitle();
2498 return inferredGenus
;
2501 private Synonym
createInferredEpithets(Taxon taxon
,
2502 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2503 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
2504 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
2505 TaxonNameBase parentName
, TaxonBase syn
) {
2507 Synonym inferredEpithet
;
2508 TaxonNameBase
<?
,?
> synName
;
2509 ZoologicalName inferredSynName
;
2510 HibernateProxyHelper
.deproxy(syn
);
2512 // Determine the idInSource
2513 String idInSourceSyn
= getIdInSource(syn
);
2514 String idInSourceTaxon
= getIdInSource(taxon
);
2515 // Determine the sourceReference
2516 Reference
<?
> sourceReference
= syn
.getSec();
2518 if (sourceReference
== null){
2519 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
2520 sourceReference
= taxon
.getSec();
2523 synName
= syn
.getName();
2524 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2525 String synGenusName
= zooSynName
.getGenusOrUninomial();
2526 String synInfraGenericEpithet
= null;
2527 String synSpecificEpithet
= null;
2529 if (zooSynName
.getInfraGenericEpithet() != null){
2530 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
2533 if (zooSynName
.isInfraSpecific()){
2534 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
2537 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2538 synonymsGenus.put(synGenusName, idInSource);
2541 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2543 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
2544 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
2545 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
2547 inferredSynName
.setGenusOrUninomial(synGenusName
);
2549 if (parentName
.isInfraGeneric()){
2550 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
2552 if (taxonName
.isSpecies()){
2553 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2554 }else if (taxonName
.isInfraSpecific()){
2555 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
2556 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
2559 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
2561 // Set the sourceReference
2562 inferredEpithet
.setSec(sourceReference
);
2564 /* Add the original source
2565 if (idInSource != null) {
2566 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
2569 Reference citation = getCitation(syn);
2570 if (citation != null) {
2571 originalSource.setCitation(citation);
2572 inferredEpithet.addSource(originalSource);
2575 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
2578 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2579 taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2581 inferredEpithet
.addSource(originalSource
);
2583 originalSource
= IdentifiableSource
.NewInstance(OriginalSourceType
.Transformation
,
2584 taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2586 inferredSynName
.addSource(originalSource
);
2590 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
2592 inferredSynName
.generateTitle();
2593 return inferredEpithet
;
2597 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
2598 * Very likely only useful for createInferredSynonyms().
2603 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2604 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
2605 if (taxonName
== null) {
2606 taxonName
= zooHashMap
.get(uuid
);
2612 * Returns the idInSource for a given Synonym.
2615 private String
getIdInSource(TaxonBase taxonBase
) {
2616 String idInSource
= null;
2617 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
2618 if (sources
.size() == 1) {
2619 IdentifiableSource source
= sources
.iterator().next();
2620 if (source
!= null) {
2621 idInSource
= source
.getIdInSource();
2623 } else if (sources
.size() > 1) {
2626 for (IdentifiableSource source
: sources
) {
2627 idInSource
+= source
.getIdInSource();
2628 if (count
< sources
.size()) {
2633 } else if (sources
.size() == 0){
2634 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
2643 * Returns the citation for a given Synonym.
2646 private Reference
getCitation(Synonym syn
) {
2647 Reference citation
= null;
2648 Set
<IdentifiableSource
> sources
= syn
.getSources();
2649 if (sources
.size() == 1) {
2650 IdentifiableSource source
= sources
.iterator().next();
2651 if (source
!= null) {
2652 citation
= source
.getCitation();
2654 } else if (sources
.size() > 1) {
2655 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
2662 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
2663 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2665 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
2666 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
2667 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
2669 return inferredSynonyms
;
2673 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listClassifications(eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)
2676 public List
<Classification
> listClassifications(TaxonBase taxonBase
, Integer limit
, Integer start
, List
<String
> propertyPaths
) {
2678 // TODO quickly implemented, create according dao !!!!
2679 Set
<TaxonNode
> nodes
= new HashSet
<TaxonNode
>();
2680 Set
<Classification
> classifications
= new HashSet
<Classification
>();
2681 List
<Classification
> list
= new ArrayList
<Classification
>();
2683 if (taxonBase
== null) {
2687 taxonBase
= load(taxonBase
.getUuid());
2689 if (taxonBase
instanceof Taxon
) {
2690 nodes
.addAll(((Taxon
)taxonBase
).getTaxonNodes());
2692 for (Taxon taxon
: ((Synonym
)taxonBase
).getAcceptedTaxa() ) {
2693 nodes
.addAll(taxon
.getTaxonNodes());
2696 for (TaxonNode node
: nodes
) {
2697 classifications
.add(node
.getClassification());
2699 list
.addAll(classifications
);