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
.HashMap
;
16 import java
.util
.HashSet
;
17 import java
.util
.Iterator
;
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
.BooleanQuery
;
28 import org
.apache
.lucene
.search
.Query
;
29 import org
.apache
.lucene
.search
.SortField
;
30 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
31 import org
.springframework
.stereotype
.Service
;
32 import org
.springframework
.transaction
.annotation
.Transactional
;
34 import eu
.etaxonomy
.cdm
.api
.service
.config
.IFindTaxaAndNamesConfigurator
;
35 import eu
.etaxonomy
.cdm
.api
.service
.config
.MatchingTaxonConfigurator
;
36 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
37 import eu
.etaxonomy
.cdm
.api
.service
.config
.SynonymDeletionConfigurator
;
38 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonBaseDeletionConfigurator
;
39 import eu
.etaxonomy
.cdm
.api
.service
.config
.TaxonDeletionConfigurator
;
40 import eu
.etaxonomy
.cdm
.api
.service
.exception
.DataChangeNoRollbackException
;
41 import eu
.etaxonomy
.cdm
.api
.service
.exception
.HomotypicalGroupChangeException
;
42 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
43 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
44 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
45 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneMultiSearch
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
.TopGroupsWithMaxScore
;
49 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
50 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
51 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
52 import eu
.etaxonomy
.cdm
.api
.service
.util
.TaxonRelationshipEdge
;
53 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
54 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
55 import eu
.etaxonomy
.cdm
.hibernate
.search
.DefinedTermBaseClassBridge
;
56 import eu
.etaxonomy
.cdm
.hibernate
.search
.GroupByTaxonClassBridge
;
57 import eu
.etaxonomy
.cdm
.hibernate
.search
.MultilanguageTextFieldBridge
;
58 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
59 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
60 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
61 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
62 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
63 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
64 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
65 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
66 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
67 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
68 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
69 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
70 import eu
.etaxonomy
.cdm
.model
.description
.IIdentificationKey
;
71 import eu
.etaxonomy
.cdm
.model
.description
.PolytomousKeyNode
;
72 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
73 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
74 import eu
.etaxonomy
.cdm
.model
.description
.TaxonInteraction
;
75 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
76 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
77 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
78 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
79 import eu
.etaxonomy
.cdm
.model
.molecular
.DnaSample
;
80 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
81 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
82 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
83 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
84 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
85 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnitBase
;
86 import eu
.etaxonomy
.cdm
.model
.occurrence
.SpecimenOrObservationBase
;
87 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
88 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
89 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
90 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
91 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
92 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
93 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
94 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
95 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
96 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
97 import eu
.etaxonomy
.cdm
.persistence
.dao
.AbstractBeanInitializer
;
98 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
99 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
100 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
101 import eu
.etaxonomy
.cdm
.persistence
.dao
.occurrence
.IOccurrenceDao
;
102 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
103 import eu
.etaxonomy
.cdm
.persistence
.fetch
.CdmFetch
;
104 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
105 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
106 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
.SortOrder
;
107 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
111 * @author a.kohlbecker
116 @Transactional(readOnly
= true)
117 public class TaxonServiceImpl
extends IdentifiableServiceBase
<TaxonBase
,ITaxonDao
> implements ITaxonService
{
118 private static final Logger logger
= Logger
.getLogger(TaxonServiceImpl
.class);
120 public static final String POTENTIAL_COMBINATION_NAMESPACE
= "Potential combination";
122 public static final String INFERRED_EPITHET_NAMESPACE
= "Inferred epithet";
124 public static final String INFERRED_GENUS_NAMESPACE
= "Inferred genus";
128 private ITaxonNameDao nameDao
;
131 private INameService nameService
;
134 private ICdmGenericDao genericDao
;
137 private IDescriptionService descriptionService
;
140 private IOrderedTermVocabularyDao orderedVocabularyDao
;
143 private IOccurrenceDao occurrenceDao
;
146 private AbstractBeanInitializer beanInitializer
;
151 public TaxonServiceImpl(){
152 if (logger
.isDebugEnabled()) { logger
.debug("Load TaxonService Bean"); }
156 * FIXME Candidate for harmonization
157 * rename searchByName ?
160 public List
<TaxonBase
> searchTaxaByName(String name
, Reference sec
) {
161 return dao
.getTaxaByName(name
, sec
);
165 * FIXME Candidate for harmonization
166 * list(Synonym.class, ...)
168 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllSynonyms(int, int)
171 public List
<Synonym
> getAllSynonyms(int limit
, int start
) {
172 return dao
.getAllSynonyms(limit
, start
);
176 * FIXME Candidate for harmonization
177 * list(Taxon.class, ...)
179 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllTaxa(int, int)
182 public List
<Taxon
> getAllTaxa(int limit
, int start
) {
183 return dao
.getAllTaxa(limit
, start
);
187 * FIXME Candidate for harmonization
188 * merge with getRootTaxa(Reference sec, ..., ...)
190 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.reference.Reference, boolean)
193 public List
<Taxon
> getRootTaxa(Reference sec
, CdmFetch cdmFetch
, boolean onlyWithChildren
) {
194 if (cdmFetch
== null){
195 cdmFetch
= CdmFetch
.NO_FETCH();
197 return dao
.getRootTaxa(sec
, cdmFetch
, onlyWithChildren
, false);
202 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getRootTaxa(eu.etaxonomy.cdm.model.name.Rank, eu.etaxonomy.cdm.model.reference.Reference, boolean, boolean)
205 public List
<Taxon
> getRootTaxa(Rank rank
, Reference sec
, boolean onlyWithChildren
,boolean withMisapplications
, List
<String
> propertyPaths
) {
206 return dao
.getRootTaxa(rank
, sec
, null, onlyWithChildren
, withMisapplications
, propertyPaths
);
210 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllRelationships(int, int)
213 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
214 return dao
.getAllRelationships(limit
, start
);
218 * FIXME Candidate for harmonization
219 * is this the same as termService.getVocabulary(VocabularyEnum.TaxonRelationshipType) ?
223 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypeVocabulary() {
225 String taxonRelTypeVocabularyId
= "15db0cf7-7afc-4a86-a7d4-221c73b0c9ac";
226 UUID uuid
= UUID
.fromString(taxonRelTypeVocabularyId
);
227 OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelTypeVocabulary
=
228 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
229 return taxonRelTypeVocabulary
;
236 * @see eu.etaxonomy.cdm.api.service.ITaxonService#swapSynonymWithAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym)
239 @Transactional(readOnly
= false)
240 public void swapSynonymAndAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
){
242 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
243 synonymName
.removeTaxonBase(synonym
);
244 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
245 taxonName
.removeTaxonBase(acceptedTaxon
);
247 synonym
.setName(taxonName
);
248 acceptedTaxon
.setName(synonymName
);
250 // the accepted taxon needs a new uuid because the concept has changed
251 // FIXME this leads to an error "HibernateException: immutable natural identifier of an instance of eu.etaxonomy.cdm.model.taxon.Taxon was altered"
252 //acceptedTaxon.setUuid(UUID.randomUUID());
257 * @see eu.etaxonomy.cdm.api.service.ITaxonService#changeSynonymToAcceptedTaxon(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
259 //TODO correct delete handling still needs to be implemented / checked
261 @Transactional(readOnly
= false)
262 public Taxon
changeSynonymToAcceptedTaxon(Synonym synonym
, Taxon acceptedTaxon
, boolean deleteSynonym
, boolean copyCitationInfo
, Reference citation
, String microCitation
) throws HomotypicalGroupChangeException
{
265 //TODO, check whether the synonym is related to the accepted taxon or not (see java doc)
266 TaxonNameBase
<?
,?
> acceptedName
= acceptedTaxon
.getName();
267 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
268 HomotypicalGroup synonymHomotypicGroup
= synonymName
.getHomotypicalGroup();
270 //check synonym is not homotypic
271 if (acceptedName
.getHomotypicalGroup().equals(synonymHomotypicGroup
)){
272 String message
= "The accepted taxon and the synonym are part of the same homotypical group and therefore can not be both accepted.";
273 throw new HomotypicalGroupChangeException(message
);
276 Taxon newAcceptedTaxon
= Taxon
.NewInstance(synonymName
, acceptedTaxon
.getSec());
278 SynonymRelationshipType relTypeForGroup
= SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF();
279 List
<Synonym
> heteroSynonyms
= acceptedTaxon
.getSynonymsInGroup(synonymHomotypicGroup
);
281 for (Synonym heteroSynonym
: heteroSynonyms
){
282 if (synonym
.equals(heteroSynonym
)){
283 acceptedTaxon
.removeSynonym(heteroSynonym
, false);
285 //move synonyms in same homotypic group to new accepted taxon
286 heteroSynonym
.replaceAcceptedTaxon(newAcceptedTaxon
, relTypeForGroup
, copyCitationInfo
, citation
, microCitation
);
290 //synonym.getName().removeTaxonBase(synonym);
291 //TODO correct delete handling still needs to be implemented / checked
293 // deleteSynonym(synonym, taxon, false);
296 this.deleteSynonym(synonym
, new SynonymDeletionConfigurator());
298 } catch (Exception e
) {
299 logger
.info("Can't delete old synonym from database");
303 return newAcceptedTaxon
;
308 public Taxon
changeSynonymToRelatedTaxon(Synonym synonym
, Taxon toTaxon
, TaxonRelationshipType taxonRelationshipType
, Reference citation
, String microcitation
){
310 // Get name from synonym
311 TaxonNameBase
<?
, ?
> synonymName
= synonym
.getName();
313 // remove synonym from taxon
314 toTaxon
.removeSynonym(synonym
);
316 // Create a taxon with synonym name
317 Taxon fromTaxon
= Taxon
.NewInstance(synonymName
, null);
319 // Add taxon relation
320 fromTaxon
.addTaxonRelation(toTaxon
, taxonRelationshipType
, citation
, microcitation
);
322 // since we are swapping names, we have to detach the name from the synonym completely.
323 // Otherwise the synonym will still be in the list of typified names.
324 synonym
.getName().removeTaxonBase(synonym
);
331 * @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)
333 @Transactional(readOnly
= false)
335 public void changeHomotypicalGroupOfSynonym(Synonym synonym
, HomotypicalGroup newHomotypicalGroup
, Taxon targetTaxon
,
336 boolean removeFromOtherTaxa
, boolean setBasionymRelationIfApplicable
){
338 TaxonNameBase synonymName
= synonym
.getName();
339 HomotypicalGroup oldHomotypicalGroup
= synonymName
.getHomotypicalGroup();
343 oldHomotypicalGroup
.removeTypifiedName(synonymName
);
344 newHomotypicalGroup
.addTypifiedName(synonymName
);
346 //remove existing basionym relationships
347 synonymName
.removeBasionyms();
349 //add basionym relationship
350 if (setBasionymRelationIfApplicable
){
351 Set
<TaxonNameBase
> basionyms
= newHomotypicalGroup
.getBasionyms();
352 for (TaxonNameBase basionym
: basionyms
){
353 synonymName
.addBasionym(basionym
);
357 //set synonym relationship correctly
358 // SynonymRelationship relToTaxon = null;
359 boolean relToTargetTaxonExists
= false;
360 Set
<SynonymRelationship
> existingRelations
= synonym
.getSynonymRelations();
361 for (SynonymRelationship rel
: existingRelations
){
362 Taxon acceptedTaxon
= rel
.getAcceptedTaxon();
363 boolean isTargetTaxon
= acceptedTaxon
!= null && acceptedTaxon
.equals(targetTaxon
);
364 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
365 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
366 SynonymRelationshipType newRelationType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
367 rel
.setType(newRelationType
);
368 //TODO handle citation and microCitation
371 relToTargetTaxonExists
= true;
373 if (removeFromOtherTaxa
){
374 acceptedTaxon
.removeSynonym(synonym
, false);
380 if (targetTaxon
!= null && ! relToTargetTaxonExists
){
381 Taxon acceptedTaxon
= targetTaxon
;
382 HomotypicalGroup acceptedGroup
= acceptedTaxon
.getHomotypicGroup();
383 boolean isHomotypicToTaxon
= acceptedGroup
.equals(newHomotypicalGroup
);
384 SynonymRelationshipType relType
= isHomotypicToTaxon? SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF() : SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
385 //TODO handle citation and microCitation
386 Reference citation
= null;
387 String microCitation
= null;
388 acceptedTaxon
.addSynonym(synonym
, relType
, citation
, microCitation
);
395 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
398 @Transactional(readOnly
= false)
399 public void updateTitleCache(Class
<?
extends TaxonBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonBase
> cacheStrategy
, IProgressMonitor monitor
) {
401 clazz
= TaxonBase
.class;
403 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
408 protected void setDao(ITaxonDao dao
) {
413 * @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)
416 public Pager
<TaxonBase
> findTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
,Integer pageNumber
) {
417 Integer numberOfResults
= dao
.countTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
419 List
<TaxonBase
> results
= new ArrayList
<TaxonBase
>();
420 if(numberOfResults
> 0) { // no point checking again
421 results
= dao
.findTaxaByName(clazz
, uninomial
, infragenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
);
424 return new DefaultPagerImpl
<TaxonBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
428 * @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)
431 public List
<TaxonBase
> listTaxaByName(Class
<?
extends TaxonBase
> clazz
, String uninomial
, String infragenericEpithet
, String specificEpithet
, 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
);
443 * @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)
446 public List
<TaxonRelationship
> listToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
447 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
449 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
450 if(numberOfResults
> 0) { // no point checking again
451 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
457 * @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)
460 public Pager
<TaxonRelationship
> pageToTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
461 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedTo
);
463 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
464 if(numberOfResults
> 0) { // no point checking again
465 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedTo
);
467 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
471 * @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)
474 public List
<TaxonRelationship
> listFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
){
475 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
477 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
478 if(numberOfResults
> 0) { // no point checking again
479 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
485 * @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)
488 public Pager
<TaxonRelationship
> pageFromTaxonRelationships(Taxon taxon
, TaxonRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
489 Integer numberOfResults
= dao
.countTaxonRelationships(taxon
, type
, TaxonRelationship
.Direction
.relatedFrom
);
491 List
<TaxonRelationship
> results
= new ArrayList
<TaxonRelationship
>();
492 if(numberOfResults
> 0) { // no point checking again
493 results
= dao
.getTaxonRelationships(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, TaxonRelationship
.Direction
.relatedFrom
);
495 return new DefaultPagerImpl
<TaxonRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
500 * @param includeRelationships
504 * @param propertyPaths
505 * @return an List which is not specifically ordered
508 public Set
<Taxon
> listRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Integer maxDepth
,
509 Integer limit
, Integer start
, List
<String
> propertyPaths
) {
511 Set
<Taxon
> relatedTaxa
= collectRelatedTaxa(taxon
, includeRelationships
, new HashSet
<Taxon
>(), maxDepth
);
512 relatedTaxa
.remove(taxon
);
513 beanInitializer
.initializeAll(relatedTaxa
, propertyPaths
);
519 * recursively collect related taxa for the given <code>taxon</code> . The returned list will also include the
520 * <code>taxon</code> supplied as parameter.
523 * @param includeRelationships
525 * @param maxDepth can be <code>null</code> for infinite depth
528 private Set
<Taxon
> collectRelatedTaxa(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, Set
<Taxon
> taxa
, Integer maxDepth
) {
534 if(maxDepth
!= null) {
537 if(logger
.isDebugEnabled()){
538 logger
.debug("collecting related taxa for " + taxon
+ " with maxDepth=" + maxDepth
);
540 List
<TaxonRelationship
> taxonRelationships
= dao
.getTaxonRelationships(taxon
, null, null, null, null, null, null);
541 for (TaxonRelationship taxRel
: taxonRelationships
) {
544 if (taxRel
.getToTaxon() == null || taxRel
.getFromTaxon() == null || taxRel
.getType() == null) {
547 // filter by includeRelationships
548 for (TaxonRelationshipEdge relationshipEdgeFilter
: includeRelationships
) {
549 if ( relationshipEdgeFilter
.getTaxonRelationshipType().equals(taxRel
.getType()) ) {
550 if (relationshipEdgeFilter
.getDirections().contains(Direction
.relatedTo
) && !taxa
.contains(taxRel
.getToTaxon())) {
551 if(logger
.isDebugEnabled()){
552 logger
.debug(maxDepth
+ ": " + taxon
.getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxRel
.getToTaxon().getTitleCache());
554 taxa
.add(taxRel
.getToTaxon());
555 if(maxDepth
== null || maxDepth
> 0) {
556 taxa
.addAll(collectRelatedTaxa(taxRel
.getToTaxon(), includeRelationships
, taxa
, maxDepth
));
559 if(relationshipEdgeFilter
.getDirections().contains(Direction
.relatedFrom
) && !taxa
.contains(taxRel
.getFromTaxon())) {
560 taxa
.add(taxRel
.getFromTaxon());
561 if(logger
.isDebugEnabled()){
562 logger
.debug(maxDepth
+ ": " +taxRel
.getFromTaxon().getTitleCache() + " --[" + taxRel
.getType().getLabel() + "]--> " + taxon
.getTitleCache() );
564 if(maxDepth
== null || maxDepth
> 0) {
565 taxa
.addAll(collectRelatedTaxa(taxRel
.getFromTaxon(), includeRelationships
, taxa
, maxDepth
));
575 * @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)
578 public Pager
<SynonymRelationship
> getSynonyms(Taxon taxon
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
579 Integer numberOfResults
= dao
.countSynonyms(taxon
, type
);
581 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
582 if(numberOfResults
> 0) { // no point checking again
583 results
= dao
.getSynonyms(taxon
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
586 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
590 * @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)
593 public Pager
<SynonymRelationship
> getSynonyms(Synonym synonym
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
594 Integer numberOfResults
= dao
.countSynonyms(synonym
, type
);
596 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
597 if(numberOfResults
> 0) { // no point checking again
598 results
= dao
.getSynonyms(synonym
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
601 return new DefaultPagerImpl
<SynonymRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
605 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHomotypicSynonymsByHomotypicGroup(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
608 public List
<Synonym
> getHomotypicSynonymsByHomotypicGroup(Taxon taxon
, List
<String
> propertyPaths
){
609 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
610 return t
.getHomotypicSynonymsByHomotypicGroup();
614 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getHeterotypicSynonymyGroups(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.List)
617 public List
<List
<Synonym
>> getHeterotypicSynonymyGroups(Taxon taxon
, List
<String
> propertyPaths
){
618 Taxon t
= (Taxon
)dao
.load(taxon
.getUuid(), propertyPaths
);
619 List
<HomotypicalGroup
> homotypicalGroups
= t
.getHeterotypicSynonymyGroups();
620 List
<List
<Synonym
>> heterotypicSynonymyGroups
= new ArrayList
<List
<Synonym
>>(homotypicalGroups
.size());
621 for(HomotypicalGroup homotypicalGroup
: homotypicalGroups
){
622 heterotypicSynonymyGroups
.add(t
.getSynonymsInGroup(homotypicalGroup
));
624 return heterotypicSynonymyGroups
;
628 public List
<UuidAndTitleCache
<TaxonBase
>> findTaxaAndNamesForEditor(IFindTaxaAndNamesConfigurator configurator
){
630 List
<UuidAndTitleCache
<TaxonBase
>> result
= new ArrayList
<UuidAndTitleCache
<TaxonBase
>>();
631 // Class<? extends TaxonBase> clazz = null;
632 // if ((configurator.isDoTaxa() && configurator.isDoSynonyms())) {
633 // clazz = TaxonBase.class;
634 // //propertyPath.addAll(configurator.getTaxonPropertyPath());
635 // //propertyPath.addAll(configurator.getSynonymPropertyPath());
636 // } else if(configurator.isDoTaxa()) {
637 // clazz = Taxon.class;
638 // //propertyPath = configurator.getTaxonPropertyPath();
639 // } else if (configurator.isDoSynonyms()) {
640 // clazz = Synonym.class;
641 // //propertyPath = configurator.getSynonymPropertyPath();
645 result
= dao
.getTaxaByNameForEditor(configurator
.isDoTaxa(), configurator
.isDoSynonyms(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
650 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaAndNames(eu.etaxonomy.cdm.api.service.config.ITaxonServiceConfigurator)
653 public Pager
<IdentifiableEntity
> findTaxaAndNames(IFindTaxaAndNamesConfigurator configurator
) {
655 List
<IdentifiableEntity
> results
= new ArrayList
<IdentifiableEntity
>();
656 int numberOfResults
= 0; // overall number of results (as opposed to number of results per page)
657 List
<TaxonBase
> taxa
= null;
660 long numberTaxaResults
= 0L;
663 List
<String
> propertyPath
= new ArrayList
<String
>();
664 if(configurator
.getTaxonPropertyPath() != null){
665 propertyPath
.addAll(configurator
.getTaxonPropertyPath());
669 if (configurator
.isDoMisappliedNames() || configurator
.isDoSynonyms() || configurator
.isDoTaxa()){
670 if(configurator
.getPageSize() != null){ // no point counting if we need all anyway
672 dao
.countTaxaByName(configurator
.isDoTaxa(),configurator
.isDoSynonyms(), configurator
.isDoMisappliedNames(),
673 configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(),
674 configurator
.getNamedAreas());
677 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){ // no point checking again if less results
678 taxa
= dao
.getTaxaByName(configurator
.isDoTaxa(), configurator
.isDoSynonyms(),
679 configurator
.isDoMisappliedNames(), configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(),
680 configurator
.getMatchMode(), configurator
.getNamedAreas(),
681 configurator
.getPageSize(), configurator
.getPageNumber(), propertyPath
);
685 if (logger
.isDebugEnabled()) { logger
.debug(numberTaxaResults
+ " matching taxa counted"); }
688 results
.addAll(taxa
);
691 numberOfResults
+= numberTaxaResults
;
693 // Names without taxa
694 if (configurator
.isDoNamesWithoutTaxa()) {
695 int numberNameResults
= 0;
697 List
<?
extends TaxonNameBase
<?
,?
>> names
=
698 nameDao
.findByName(configurator
.getTitleSearchStringSqlized(), configurator
.getMatchMode(),
699 configurator
.getPageSize(), configurator
.getPageNumber(), null, configurator
.getTaxonNamePropertyPath());
700 if (logger
.isDebugEnabled()) { logger
.debug(names
.size() + " matching name(s) found"); }
701 if (names
.size() > 0) {
702 for (TaxonNameBase
<?
,?
> taxonName
: names
) {
703 if (taxonName
.getTaxonBases().size() == 0) {
704 results
.add(taxonName
);
708 if (logger
.isDebugEnabled()) { logger
.debug(numberNameResults
+ " matching name(s) without taxa found"); }
709 numberOfResults
+= numberNameResults
;
713 // Taxa from common names
715 if (configurator
.isDoTaxaByCommonNames()) {
716 taxa
= new ArrayList
<TaxonBase
>();
717 numberTaxaResults
= 0;
718 if(configurator
.getPageSize() != null){// no point counting if we need all anyway
719 numberTaxaResults
= dao
.countTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas());
721 if(configurator
.getPageSize() == null || numberTaxaResults
> configurator
.getPageSize() * configurator
.getPageNumber()){
722 List
<Object
[]> commonNameResults
= dao
.getTaxaByCommonName(configurator
.getTitleSearchStringSqlized(), configurator
.getClassification(), configurator
.getMatchMode(), configurator
.getNamedAreas(), configurator
.getPageSize(), configurator
.getPageNumber(), configurator
.getTaxonPropertyPath());
723 for( Object
[] entry
: commonNameResults
) {
724 taxa
.add((TaxonBase
) entry
[0]);
728 results
.addAll(taxa
);
730 numberOfResults
+= numberTaxaResults
;
734 return new DefaultPagerImpl
<IdentifiableEntity
>
735 (configurator
.getPageNumber(), numberOfResults
, configurator
.getPageSize(), results
);
738 public List
<UuidAndTitleCache
<TaxonBase
>> getTaxonUuidAndTitleCache(){
739 return dao
.getUuidAndTitleCache();
743 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getAllMedia(eu.etaxonomy.cdm.model.taxon.Taxon, int, int, int, java.lang.String[])
746 public List
<MediaRepresentation
> getAllMedia(Taxon taxon
, int size
, int height
, int widthOrDuration
, String
[] mimeTypes
){
747 List
<MediaRepresentation
> medRep
= new ArrayList
<MediaRepresentation
>();
748 taxon
= (Taxon
)dao
.load(taxon
.getUuid());
749 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
750 for (TaxonDescription taxDesc
: descriptions
){
751 Set
<DescriptionElementBase
> elements
= taxDesc
.getElements();
752 for (DescriptionElementBase descElem
: elements
){
753 for(Media media
: descElem
.getMedia()){
755 //find the best matching representation
756 medRep
.add(MediaUtils
.findBestMatchingRepresentation(media
, null, size
, height
, widthOrDuration
, mimeTypes
));
765 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listTaxonDescriptionMedia(eu.etaxonomy.cdm.model.taxon.Taxon, boolean)
768 public List
<Media
> listTaxonDescriptionMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
, boolean limitToGalleries
, List
<String
> propertyPath
){
769 return listMedia(taxon
, includeRelationships
, limitToGalleries
, true, false, false, propertyPath
);
774 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listMedia(eu.etaxonomy.cdm.model.taxon.Taxon, java.util.Set, boolean, java.util.List)
777 public List
<Media
> listMedia(Taxon taxon
, Set
<TaxonRelationshipEdge
> includeRelationships
,
778 Boolean limitToGalleries
, Boolean includeTaxonDescriptions
, Boolean includeOccurrences
,
779 Boolean includeTaxonNameDescriptions
, List
<String
> propertyPath
) {
781 Set
<Taxon
> taxa
= new HashSet
<Taxon
>();
782 List
<Media
> taxonMedia
= new ArrayList
<Media
>();
784 if (limitToGalleries
== null) {
785 limitToGalleries
= false;
788 // --- resolve related taxa
789 if (includeRelationships
!= null) {
790 taxa
= listRelatedTaxa(taxon
, includeRelationships
, null, null, null, null);
793 taxa
.add((Taxon
) dao
.load(taxon
.getUuid()));
795 if(includeTaxonDescriptions
!= null && includeTaxonDescriptions
){
796 List
<TaxonDescription
> taxonDescriptions
= new ArrayList
<TaxonDescription
>();
797 // --- TaxonDescriptions
798 for (Taxon t
: taxa
) {
799 taxonDescriptions
.addAll(descriptionService
.listTaxonDescriptions(t
, null, null, null, null, propertyPath
));
801 for (TaxonDescription taxonDescription
: taxonDescriptions
) {
802 if (!limitToGalleries
|| taxonDescription
.isImageGallery()) {
803 for (DescriptionElementBase element
: taxonDescription
.getElements()) {
804 for (Media media
: element
.getMedia()) {
805 taxonMedia
.add(media
);
812 if(includeOccurrences
!= null && includeOccurrences
) {
813 Set
<SpecimenOrObservationBase
> specimensOrObservations
= new HashSet
<SpecimenOrObservationBase
>();
815 for (Taxon t
: taxa
) {
816 specimensOrObservations
.addAll(occurrenceDao
.listByAssociatedTaxon(null, t
, null, null, null, null));
818 for (SpecimenOrObservationBase occurrence
: specimensOrObservations
) {
820 taxonMedia
.addAll(occurrence
.getMedia());
822 // SpecimenDescriptions
823 Set
<SpecimenDescription
> specimenDescriptions
= occurrence
.getSpecimenDescriptions();
824 for (DescriptionBase specimenDescription
: specimenDescriptions
) {
825 if (!limitToGalleries
|| specimenDescription
.isImageGallery()) {
826 Set
<DescriptionElementBase
> elements
= specimenDescription
.getElements();
827 for (DescriptionElementBase element
: elements
) {
828 for (Media media
: element
.getMedia()) {
829 taxonMedia
.add(media
);
836 if (occurrence
instanceof DerivedUnitBase
) {
837 if (((DerivedUnitBase
) occurrence
).getCollection() != null){
838 taxonMedia
.addAll(((DerivedUnitBase
) occurrence
).getCollection().getMedia());
843 if (occurrence
instanceof DnaSample
) {
844 Set
<Sequence
> sequences
= ((DnaSample
) occurrence
).getSequences();
845 for (Sequence sequence
: sequences
) {
846 taxonMedia
.addAll(sequence
.getChromatograms());
853 if(includeTaxonNameDescriptions
!= null && includeTaxonNameDescriptions
) {
854 // --- TaxonNameDescription
855 Set
<TaxonNameDescription
> nameDescriptions
= new HashSet
<TaxonNameDescription
>();
856 for (Taxon t
: taxa
) {
857 nameDescriptions
.addAll(t
.getName().getDescriptions());
859 for(TaxonNameDescription nameDescription
: nameDescriptions
){
860 if (!limitToGalleries
|| nameDescription
.isImageGallery()) {
861 Set
<DescriptionElementBase
> elements
= nameDescription
.getElements();
862 for (DescriptionElementBase element
: elements
) {
863 for (Media media
: element
.getMedia()) {
864 taxonMedia
.add(media
);
871 beanInitializer
.initializeAll(taxonMedia
, propertyPath
);
876 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxaByID(java.util.Set)
879 public List
<TaxonBase
> findTaxaByID(Set
<Integer
> listOfIDs
) {
880 return this.dao
.listByIds(listOfIDs
, null, null, null, null);
884 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findTaxonByUuid(UUID uuid, List<String> propertyPaths)
887 public TaxonBase
findTaxonByUuid(UUID uuid
, List
<String
> propertyPaths
){
888 return this.dao
.findByUuid(uuid
, null ,propertyPaths
);
892 * @see eu.etaxonomy.cdm.api.service.ITaxonService#countAllRelationships()
895 public int countAllRelationships() {
896 return this.dao
.countAllRelationships();
903 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNames(java.util.List)
906 public List
<TaxonNameBase
> findIdenticalTaxonNames(List
<String
> propertyPath
) {
907 return this.dao
.findIdenticalTaxonNames(propertyPath
);
912 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteTaxon(eu.etaxonomy.cdm.model.taxon.Taxon, eu.etaxonomy.cdm.api.service.config.TaxonDeletionConfigurator)
915 public void deleteTaxon(Taxon taxon
, TaxonDeletionConfigurator config
, Classification classification
) throws ReferencedObjectUndeletableException
{
917 config
= new TaxonDeletionConfigurator();
921 if (! config
.isDeleteTaxonNodes()){
922 if (taxon
.getTaxonNodes().size() > 0){
923 String message
= "Taxon can't be deleted as it is used in a classification node. Remove taxon from all classifications prior to deletion.";
924 throw new ReferencedObjectUndeletableException(message
);
927 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
928 Iterator
<TaxonNode
> iterator
= nodes
.iterator();
930 if (config
.getTaxonNodeConfig().isDeleteInAllClassifications()){
931 taxon
.removeTaxonNodes();
933 while (iterator
.hasNext()){
934 node
= iterator
.next();
935 if (node
.getClassification().equals(classification
)){
946 // SynonymRelationShip
947 if (config
.isDeleteSynonymRelations()){
948 boolean removeSynonymNameFromHomotypicalGroup
= false;
949 for (SynonymRelationship synRel
: taxon
.getSynonymRelations()){
950 Synonym synonym
= synRel
.getSynonym();
951 taxon
.removeSynonymRelation(synRel
, removeSynonymNameFromHomotypicalGroup
);
952 if (config
.isDeleteSynonymsIfPossible()){
954 boolean newHomotypicGroupIfNeeded
= true;
955 SynonymDeletionConfigurator synConfig
= new SynonymDeletionConfigurator();
957 deleteSynonym(synonym
, taxon
, synConfig
);
959 deleteSynonymRelationships(synonym
, taxon
);
965 if (! config
.isDeleteTaxonRelationships()){
966 if (taxon
.getTaxonRelations().size() > 0){
967 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.";
968 throw new ReferencedObjectUndeletableException(message
);
977 //check references with only reverse mapping
978 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(taxon
);
979 for (CdmBase referencingObject
: referencingObjects
){
980 //IIdentificationKeys (Media, Polytomous, MultiAccess)
981 if (HibernateProxyHelper
.isInstanceOf(referencingObject
, IIdentificationKey
.class)){
982 String message
= "Taxon can't be deleted as it is used in an identification key. Remove from identification key prior to deleting this name";
983 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnitBase
.class).getTitleCache());
984 throw new ReferencedObjectUndeletableException(message
);
989 if (referencingObject
.isInstanceOf(PolytomousKeyNode
.class)){
990 String message
= "Taxon can't be deleted as it is used in polytomous key node";
991 throw new ReferencedObjectUndeletableException(message
);
995 if (referencingObject
.isInstanceOf(TaxonInteraction
.class)){
996 String message
= "Taxon can't be deleted as it is used in taxonInteraction#taxon2";
997 throw new ReferencedObjectUndeletableException(message
);
1003 if (config
.isDeleteNameIfPossible()){
1005 TaxonNameBase name
= nameService
.find(taxon
.getName().getUuid());
1007 nameService
.save(name
);
1008 nameService
.delete(taxon
.getName(), config
.getNameDeletionConfig());
1009 } catch (ReferencedObjectUndeletableException e
) {
1011 if (logger
.isDebugEnabled()){logger
.debug("Name could not be deleted");}
1016 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
1018 for (TaxonDescription desc
: descriptions
){
1019 if (config
.isDeleteDescriptions()){
1020 //TODO use description delete configurator ?
1021 //FIXME check if description is ALWAYS deletable
1022 taxon
.removeDescription(desc
);
1023 descriptionService
.delete(desc
);
1025 if (desc
.getDescribedSpecimenOrObservations().size()>0){
1026 String message
= "Taxon can't be deleted as it is used in a TaxonDescription" +
1027 " which also describes specimens or abservations";
1028 throw new ReferencedObjectUndeletableException(message
);
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
, SynonymDeletionConfigurator config
) {
1043 deleteSynonym(synonym
, null, config
);
1049 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonym(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon, boolean, boolean)
1051 @Transactional(readOnly
= false)
1053 public void deleteSynonym(Synonym synonym
, Taxon taxon
, SynonymDeletionConfigurator config
) {
1054 if (synonym
== null){
1057 synonym
= CdmBase
.deproxy(dao
.merge(synonym
), Synonym
.class);
1059 //remove synonymRelationship
1060 Set
<Taxon
> taxonSet
= new HashSet
<Taxon
>();
1062 taxonSet
.add(taxon
);
1064 taxonSet
.addAll(synonym
.getAcceptedTaxa());
1066 for (Taxon relatedTaxon
: taxonSet
){
1067 // dao.deleteSynonymRelationships(synonym, relatedTaxon);
1068 relatedTaxon
.removeSynonym(synonym
, config
.isNewHomotypicGroupIfNeeded());
1070 this.saveOrUpdate(synonym
);
1072 //TODO remove name from homotypical group?
1074 //remove synonym (if necessary)
1077 if (synonym
.getSynonymRelations().isEmpty()){
1078 TaxonNameBase
<?
,?
> name
= synonym
.getName();
1079 synonym
.setName(null);
1080 dao
.delete(synonym
);
1082 //remove name if possible (and required)
1083 if (name
!= null && config
.isDeleteNameIfPossible()){
1085 nameService
.delete(name
, config
.getNameDeletionConfig());
1086 }catch (DataChangeNoRollbackException ex
){
1087 if (logger
.isDebugEnabled()) {
1088 logger
.debug("Name wasn't deleted as it is referenced");
1097 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findIdenticalTaxonNameIds(java.util.List)
1100 public List
<TaxonNameBase
> findIdenticalTaxonNameIds(List
<String
> propertyPath
) {
1102 return this.dao
.findIdenticalNamesNew(propertyPath
);
1106 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getPhylumName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1109 public String
getPhylumName(TaxonNameBase name
){
1110 return this.dao
.getPhylumName(name
);
1114 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym, eu.etaxonomy.cdm.model.taxon.Taxon)
1117 public long deleteSynonymRelationships(Synonym syn
, Taxon taxon
) {
1118 return dao
.deleteSynonymRelationships(syn
, taxon
);
1122 * @see eu.etaxonomy.cdm.api.service.ITaxonService#deleteSynonymRelationships(eu.etaxonomy.cdm.model.taxon.Synonym)
1125 public long deleteSynonymRelationships(Synonym syn
) {
1126 return dao
.deleteSynonymRelationships(syn
, null);
1131 * @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)
1134 public List
<SynonymRelationship
> listSynonymRelationships(
1135 TaxonBase taxonBase
, SynonymRelationshipType type
, Integer pageSize
, Integer pageNumber
,
1136 List
<OrderHint
> orderHints
, List
<String
> propertyPaths
, Direction direction
) {
1137 Integer numberOfResults
= dao
.countSynonymRelationships(taxonBase
, type
, direction
);
1139 List
<SynonymRelationship
> results
= new ArrayList
<SynonymRelationship
>();
1140 if(numberOfResults
> 0) { // no point checking again
1141 results
= dao
.getSynonymRelationships(taxonBase
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
, direction
);
1147 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingTaxon(java.lang.String)
1150 public Taxon
findBestMatchingTaxon(String taxonName
) {
1151 MatchingTaxonConfigurator config
= MatchingTaxonConfigurator
.NewInstance();
1152 config
.setTaxonNameTitle(taxonName
);
1153 return findBestMatchingTaxon(config
);
1159 public Taxon
findBestMatchingTaxon(MatchingTaxonConfigurator config
) {
1161 Taxon bestCandidate
= null;
1163 // 1. search for acceptet taxa
1164 List
<TaxonBase
> taxonList
= dao
.findByNameTitleCache(true, false, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1165 boolean bestCandidateMatchesSecUuid
= false;
1166 boolean bestCandidateIsInClassification
= false;
1167 int countEqualCandidates
= 0;
1168 for(TaxonBase taxonBaseCandidate
: taxonList
){
1169 if(taxonBaseCandidate
instanceof Taxon
){
1170 Taxon newCanditate
= CdmBase
.deproxy(taxonBaseCandidate
, Taxon
.class);
1171 boolean newCandidateMatchesSecUuid
= isMatchesSecUuid(newCanditate
, config
);
1172 if (! newCandidateMatchesSecUuid
&& config
.isOnlyMatchingSecUuid() ){
1174 }else if(newCandidateMatchesSecUuid
&& ! bestCandidateMatchesSecUuid
){
1175 bestCandidate
= newCanditate
;
1176 countEqualCandidates
= 1;
1177 bestCandidateMatchesSecUuid
= true;
1181 boolean newCandidateInClassification
= isInClassification(newCanditate
, config
);
1182 if (! newCandidateInClassification
&& config
.isOnlyMatchingClassificationUuid()){
1184 }else if (newCandidateInClassification
&& ! bestCandidateIsInClassification
){
1185 bestCandidate
= newCanditate
;
1186 countEqualCandidates
= 1;
1187 bestCandidateIsInClassification
= true;
1190 if (bestCandidate
== null){
1191 bestCandidate
= newCanditate
;
1192 countEqualCandidates
= 1;
1196 }else{ //not Taxon.class
1199 countEqualCandidates
++;
1202 if (bestCandidate
!= null){
1203 if(countEqualCandidates
> 1){
1204 logger
.info(countEqualCandidates
+ " equally matching TaxonBases found, using first accepted Taxon: " + bestCandidate
.getTitleCache());
1205 return bestCandidate
;
1207 logger
.info("using accepted Taxon: " + bestCandidate
.getTitleCache());
1208 return bestCandidate
;
1213 // 2. search for synonyms
1214 if (config
.isIncludeSynonyms()){
1215 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, config
.getTaxonNameTitle(), null, MatchMode
.EXACT
, null, 0, null, null);
1216 for(TaxonBase taxonBase
: synonymList
){
1217 if(taxonBase
instanceof Synonym
){
1218 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
1219 Set
<Taxon
> acceptetdCandidates
= synonym
.getAcceptedTaxa();
1220 if(!acceptetdCandidates
.isEmpty()){
1221 bestCandidate
= acceptetdCandidates
.iterator().next();
1222 if(acceptetdCandidates
.size() == 1){
1223 logger
.info(acceptetdCandidates
.size() + " Accepted taxa found for synonym " + taxonBase
.getTitleCache() + ", using first one: " + bestCandidate
.getTitleCache());
1224 return bestCandidate
;
1226 logger
.info("using accepted Taxon " + bestCandidate
.getTitleCache() + "for synonym " + taxonBase
.getTitleCache());
1227 return bestCandidate
;
1229 //TODO extend method: search using treeUUID, using SecUUID, first find accepted then include synonyms until a matching taxon is found
1235 } catch (Exception e
){
1239 return bestCandidate
;
1242 private boolean isInClassification(Taxon taxon
, MatchingTaxonConfigurator config
) {
1243 UUID configClassificationUuid
= config
.getClassificationUuid();
1244 if (configClassificationUuid
== null){
1247 for (TaxonNode node
: taxon
.getTaxonNodes()){
1248 UUID classUuid
= node
.getClassification().getUuid();
1249 if (configClassificationUuid
.equals(classUuid
)){
1256 private boolean isMatchesSecUuid(Taxon taxon
, MatchingTaxonConfigurator config
) {
1257 UUID configSecUuid
= config
.getSecUuid();
1258 if (configSecUuid
== null){
1261 UUID taxonSecUuid
= (taxon
.getSec() == null)?
null : taxon
.getSec().getUuid();
1262 return configSecUuid
.equals(taxonSecUuid
);
1266 * @see eu.etaxonomy.cdm.api.service.ITaxonService#findBestMatchingSynonym(java.lang.String)
1269 public Synonym
findBestMatchingSynonym(String taxonName
) {
1270 List
<TaxonBase
> synonymList
= dao
.findByNameTitleCache(false, true, taxonName
, null, MatchMode
.EXACT
, null, 0, null, null);
1271 if(! synonymList
.isEmpty()){
1272 Synonym result
= CdmBase
.deproxy(synonymList
.iterator().next(), Synonym
.class);
1273 if(synonymList
.size() == 1){
1274 logger
.info(synonymList
.size() + " Synonym found " + result
.getTitleCache() );
1277 logger
.info("Several matching synonyms found. Using first: " + result
.getTitleCache());
1286 * @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)
1289 public SynonymRelationship
moveSynonymToAnotherTaxon(SynonymRelationship oldSynonymRelation
, Taxon newTaxon
, boolean moveHomotypicGroup
,
1290 SynonymRelationshipType newSynonymRelationshipType
, Reference reference
, String referenceDetail
, boolean keepReference
) throws HomotypicalGroupChangeException
{
1292 Synonym synonym
= oldSynonymRelation
.getSynonym();
1293 Taxon fromTaxon
= oldSynonymRelation
.getAcceptedTaxon();
1294 //TODO what if there is no name ?? Concepts may be cached (e.g. via TCS import)
1295 TaxonNameBase
<?
,?
> synonymName
= synonym
.getName();
1296 TaxonNameBase
<?
,?
> fromTaxonName
= fromTaxon
.getName();
1297 //set default relationship type
1298 if (newSynonymRelationshipType
== null){
1299 newSynonymRelationshipType
= SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF();
1301 boolean newRelTypeIsHomotypic
= newSynonymRelationshipType
.equals(SynonymRelationshipType
.HOMOTYPIC_SYNONYM_OF());
1303 HomotypicalGroup homotypicGroup
= synonymName
.getHomotypicalGroup();
1304 int hgSize
= homotypicGroup
.getTypifiedNames().size();
1305 boolean isSingleInGroup
= !(hgSize
> 1);
1307 if (! isSingleInGroup
){
1308 boolean isHomotypicToAccepted
= synonymName
.isHomotypic(fromTaxonName
);
1309 boolean hasHomotypicSynonymRelatives
= isHomotypicToAccepted ? hgSize
> 2 : hgSize
> 1;
1310 if (isHomotypicToAccepted
){
1311 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.";
1312 String homotypicRelatives
= hasHomotypicSynonymRelatives ?
" and other synonym(s)":"";
1313 message
= String
.format(message
, homotypicRelatives
);
1314 throw new HomotypicalGroupChangeException(message
);
1316 if (! moveHomotypicGroup
){
1317 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.";
1318 throw new HomotypicalGroupChangeException(message
);
1321 moveHomotypicGroup
= true; //single synonym always allows to moveCompleteGroup
1323 // Assert.assertTrue("Synonym can only be moved with complete homotypic group", moveHomotypicGroup);
1325 SynonymRelationship result
= null;
1326 //move all synonyms to new taxon
1327 List
<Synonym
> homotypicSynonyms
= fromTaxon
.getSynonymsInGroup(homotypicGroup
);
1328 for (Synonym syn
: homotypicSynonyms
){
1329 Set
<SynonymRelationship
> synRelations
= syn
.getSynonymRelations();
1330 for (SynonymRelationship synRelation
: synRelations
){
1331 if (fromTaxon
.equals(synRelation
.getAcceptedTaxon())){
1332 Reference
<?
> newReference
= reference
;
1333 if (newReference
== null && keepReference
){
1334 newReference
= synRelation
.getCitation();
1336 String newRefDetail
= referenceDetail
;
1337 if (newRefDetail
== null && keepReference
){
1338 newRefDetail
= synRelation
.getCitationMicroReference();
1340 SynonymRelationship newSynRelation
= newTaxon
.addSynonym(syn
, newSynonymRelationshipType
, newReference
, newRefDetail
);
1341 fromTaxon
.removeSynonymRelation(synRelation
, false);
1343 //change homotypic group of synonym if relType is 'homotypic'
1344 // if (newRelTypeIsHomotypic){
1345 // newTaxon.getName().getHomotypicalGroup().addTypifiedName(syn.getName());
1348 if (synRelation
.equals(oldSynonymRelation
)){
1349 result
= newSynRelation
;
1355 saveOrUpdate(newTaxon
);
1356 //Assert that there is a result
1357 if (result
== null){
1358 String message
= "Old synonym relation could not be transformed into new relation. This should not happen.";
1359 throw new IllegalStateException(message
);
1365 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheTaxon()
1368 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheTaxon() {
1369 return dao
.getUuidAndTitleCacheTaxon();
1373 * @see eu.etaxonomy.cdm.api.service.ITaxonService#getUuidAndTitleCacheSynonym()
1376 public List
<UuidAndTitleCache
<TaxonBase
>> getUuidAndTitleCacheSynonym() {
1377 return dao
.getUuidAndTitleCacheSynonym();
1381 * @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)
1384 public Pager
<SearchResult
<TaxonBase
>> findByFullText(
1385 Class
<?
extends TaxonBase
> clazz
, String queryString
,
1386 Classification classification
, List
<Language
> languages
,
1387 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1390 LuceneSearch luceneSearch
= prepareFindByFullTextSearch(clazz
, queryString
, classification
, languages
, highlightFragments
);
1392 // --- execute search
1393 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1395 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1396 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1398 // --- initialize taxa, thighlight matches ....
1399 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1400 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1401 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1403 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupedHitCount
: 0;
1404 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1409 * @param queryString
1410 * @param classification
1412 * @param highlightFragments
1413 * @param directorySelectClass
1416 protected LuceneSearch
prepareFindByFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Language
> languages
,
1417 boolean highlightFragments
) {
1418 BooleanQuery finalQuery
= new BooleanQuery();
1419 BooleanQuery textQuery
= new BooleanQuery();
1421 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), TaxonBase
.class);
1422 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1424 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("titleCache__sort", SortField
.STRING
, false)};
1425 luceneSearch
.setSortFields(sortFields
);
1427 // ---- search criteria
1428 luceneSearch
.setClazz(clazz
);
1430 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1431 textQuery
.add(queryFactory
.newDefinedTermQuery("name.rank", queryString
, languages
), Occur
.SHOULD
);
1433 finalQuery
.add(textQuery
, Occur
.MUST
);
1435 if(classification
!= null){
1436 finalQuery
.add(queryFactory
.newEntityIdQuery("taxonNodes.classification.id", classification
), Occur
.MUST
);
1438 luceneSearch
.setQuery(finalQuery
);
1440 if(highlightFragments
){
1441 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1443 return luceneSearch
;
1448 * @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)
1451 public Pager
<SearchResult
<TaxonBase
>> findByDescriptionElementFullText(
1452 Class
<?
extends DescriptionElementBase
> clazz
, String queryString
,
1453 Classification classification
, List
<Feature
> features
, List
<Language
> languages
,
1454 boolean highlightFragments
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1457 LuceneSearch luceneSearch
= prepareByDescriptionElementFullTextSearch(clazz
, queryString
, classification
, features
, languages
, highlightFragments
);
1459 // --- execute search
1460 TopGroupsWithMaxScore topDocsResultSet
= luceneSearch
.executeSearch(pageSize
, pageNumber
);
1462 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1463 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1465 // --- initialize taxa, highlight matches ....
1466 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
1467 @SuppressWarnings("rawtypes")
1468 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1469 topDocsResultSet
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1471 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupCount
: 0;
1472 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1478 public Pager
<SearchResult
<TaxonBase
>> findByEverythingFullText(String queryString
,
1479 Classification classification
, List
<Language
> languages
, boolean highlightFragments
,
1480 Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) throws CorruptIndexException
, IOException
, ParseException
{
1482 LuceneSearch luceneSearchByDescriptionElement
= prepareByDescriptionElementFullTextSearch(null, queryString
, classification
, null, languages
, highlightFragments
);
1483 LuceneSearch luceneSearchByTaxonBase
= prepareFindByFullTextSearch(null, queryString
, classification
, languages
, highlightFragments
);
1485 LuceneMultiSearch multiSearch
= new LuceneMultiSearch(luceneSearchByDescriptionElement
, luceneSearchByTaxonBase
);
1487 // --- execute search
1488 TopGroupsWithMaxScore topDocsResultSet
= multiSearch
.executeSearch(pageSize
, pageNumber
);
1490 // --- initialize taxa, highlight matches ....
1491 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(multiSearch
, multiSearch
.getQuery());
1493 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
1494 idFieldMap
.put(CdmBaseType
.TAXON
, "id");
1495 idFieldMap
.put(CdmBaseType
.DESCRIPTION_ELEMENT
, "inDescription.taxon.id");
1497 List
<SearchResult
<TaxonBase
>> searchResults
= searchResultBuilder
.createResultSet(
1498 topDocsResultSet
, multiSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
1500 int totalHits
= topDocsResultSet
!= null ? topDocsResultSet
.topGroups
.totalGroupedHitCount
: 0;
1501 return new DefaultPagerImpl
<SearchResult
<TaxonBase
>>(pageNumber
, totalHits
, pageSize
, searchResults
);
1508 * @param queryString
1509 * @param classification
1512 * @param highlightFragments
1513 * @param directorySelectClass
1516 protected LuceneSearch
prepareByDescriptionElementFullTextSearch(Class
<?
extends CdmBase
> clazz
, String queryString
, Classification classification
, List
<Feature
> features
,
1517 List
<Language
> languages
, boolean highlightFragments
) {
1518 BooleanQuery finalQuery
= new BooleanQuery();
1519 BooleanQuery textQuery
= new BooleanQuery();
1521 LuceneSearch luceneSearch
= new LuceneSearch(getSession(), GroupByTaxonClassBridge
.GROUPBY_TAXON_FIELD
, DescriptionElementBase
.class);
1522 QueryFactory queryFactory
= new QueryFactory(luceneSearch
);
1524 SortField
[] sortFields
= new SortField
[]{SortField
.FIELD_SCORE
, new SortField("inDescription.taxon.titleCache__sort", SortField
.STRING
, false)};
1525 luceneSearch
.setSortFields(sortFields
);
1527 // ---- search criteria
1528 luceneSearch
.setClazz(clazz
);
1529 textQuery
.add(queryFactory
.newTermQuery("titleCache", queryString
), Occur
.SHOULD
);
1533 if(languages
== null || languages
.size() == 0){
1534 nameQuery
= queryFactory
.newTermQuery("name", queryString
);
1536 nameQuery
= new BooleanQuery();
1537 BooleanQuery languageSubQuery
= new BooleanQuery();
1538 for(Language lang
: languages
){
1539 languageSubQuery
.add(queryFactory
.newTermQuery("language.uuid", lang
.getUuid().toString(), false), Occur
.SHOULD
);
1541 ((BooleanQuery
) nameQuery
).add(queryFactory
.newTermQuery("name", queryString
), Occur
.MUST
);
1542 ((BooleanQuery
) nameQuery
).add(languageSubQuery
, Occur
.MUST
);
1544 textQuery
.add(nameQuery
, Occur
.SHOULD
);
1547 // text field from TextData
1548 textQuery
.add(queryFactory
.newMultilanguageTextQuery("text", queryString
, languages
), Occur
.SHOULD
);
1550 // --- TermBase fields - by representation ----
1551 // state field from CategoricalData
1552 textQuery
.add(queryFactory
.newDefinedTermQuery("states.state", queryString
, languages
), Occur
.SHOULD
);
1554 // state field from CategoricalData
1555 textQuery
.add(queryFactory
.newDefinedTermQuery("states.modifyingText", queryString
, languages
), Occur
.SHOULD
);
1557 // area field from Distribution
1558 textQuery
.add(queryFactory
.newDefinedTermQuery("area", queryString
, languages
), Occur
.SHOULD
);
1560 // status field from Distribution
1561 textQuery
.add(queryFactory
.newDefinedTermQuery("status", queryString
, languages
), Occur
.SHOULD
);
1563 finalQuery
.add(textQuery
, Occur
.MUST
);
1564 // --- classification ----
1566 if(classification
!= null){
1567 finalQuery
.add(queryFactory
.newEntityIdQuery("inDescription.taxon.taxonNodes.classification.id", classification
), Occur
.MUST
);
1570 // --- IdentifieableEntity fields - by uuid
1571 if(features
!= null && features
.size() > 0 ){
1572 finalQuery
.add(queryFactory
.newEntityUuidQuery("feature.uuid", features
), Occur
.MUST
);
1575 // the description must be associated with a taxon
1576 finalQuery
.add(queryFactory
.newIsNotNullQuery("inDescription.taxon.id"), Occur
.MUST
);
1578 logger
.info("prepareByDescriptionElementFullTextSearch() query: " + finalQuery
.toString());
1579 luceneSearch
.setQuery(finalQuery
);
1581 if(highlightFragments
){
1582 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
1584 return luceneSearch
;
1588 * DefinedTerm representations and MultilanguageString maps are stored in the Lucene index by the {@link DefinedTermBaseClassBridge}
1589 * and {@link MultilanguageTextFieldBridge } in a consistent way. One field per language and also in one additional field for all languages.
1590 * This method is a convenient means to retrieve a Lucene query string for such the fields.
1592 * @param name name of the term field as in the Lucene index. Must be field created by {@link DefinedTermBaseClassBridge}
1593 * or {@link MultilanguageTextFieldBridge }
1594 * @param languages the languages to search for exclusively. Can be <code>null</code> to search in all languages
1595 * @param stringBuilder a StringBuilder to be reused, if <code>null</code> a new StringBuilder will be instantiated and is returned
1596 * @return the StringBuilder given a parameter or a new one if the stringBuilder parameter was null.
1598 * TODO move to utiliy class !!!!!!!!
1600 private StringBuilder
appendLocalizedFieldQuery(String name
, List
<Language
> languages
, StringBuilder stringBuilder
) {
1602 if(stringBuilder
== null){
1603 stringBuilder
= new StringBuilder();
1605 if(languages
== null || languages
.size() == 0){
1606 stringBuilder
.append(name
+ ".ALL:(%1$s) ");
1608 for(Language lang
: languages
){
1609 stringBuilder
.append(name
+ "." + lang
.getUuid().toString() + ":(%1$s) ");
1612 return stringBuilder
;
1616 public List
<Synonym
> createInferredSynonyms(Taxon taxon
, Classification classification
, SynonymRelationshipType type
, boolean doWithMisappliedNames
){
1617 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
1618 List
<Synonym
> inferredSynonymsToBeRemoved
= new ArrayList
<Synonym
>();
1620 HashMap
<UUID
, ZoologicalName
> zooHashMap
= new HashMap
<UUID
, ZoologicalName
>();
1623 UUID nameUuid
= taxon
.getName().getUuid();
1624 ZoologicalName taxonName
= getZoologicalName(nameUuid
, zooHashMap
);
1625 String epithetOfTaxon
= null;
1626 String infragenericEpithetOfTaxon
= null;
1627 String infraspecificEpithetOfTaxon
= null;
1628 if (taxonName
.isSpecies()){
1629 epithetOfTaxon
= taxonName
.getSpecificEpithet();
1630 } else if (taxonName
.isInfraGeneric()){
1631 infragenericEpithetOfTaxon
= taxonName
.getInfraGenericEpithet();
1632 } else if (taxonName
.isInfraSpecific()){
1633 infraspecificEpithetOfTaxon
= taxonName
.getInfraSpecificEpithet();
1635 String genusOfTaxon
= taxonName
.getGenusOrUninomial();
1636 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1637 List
<String
> taxonNames
= new ArrayList
<String
>();
1639 for (TaxonNode node
: nodes
){
1640 // HashMap<String, String> synonymsGenus = new HashMap<String, String>(); // Changed this to be able to store the idInSource to a genusName
1641 // List<String> synonymsEpithet = new ArrayList<String>();
1643 if (node
.getClassification().equals(classification
)){
1644 if (!node
.isTopmostNode()){
1645 TaxonNode parent
= node
.getParent();
1646 parent
= (TaxonNode
)HibernateProxyHelper
.deproxy(parent
);
1647 TaxonNameBase
<?
,?
> parentName
= parent
.getTaxon().getName();
1648 ZoologicalName zooParentName
= HibernateProxyHelper
.deproxy(parentName
, ZoologicalName
.class);
1649 Taxon parentTaxon
= (Taxon
)HibernateProxyHelper
.deproxy(parent
.getTaxon());
1650 Rank rankOfTaxon
= taxonName
.getRank();
1653 //create inferred synonyms for species, subspecies
1654 if ((parentName
.isGenus() || parentName
.isSpecies() || parentName
.getRank().equals(Rank
.SUBGENUS())) ){
1656 Synonym inferredEpithet
= null;
1657 Synonym inferredGenus
= null;
1658 Synonym potentialCombination
= null;
1660 List
<String
> propertyPaths
= new ArrayList
<String
>();
1661 propertyPaths
.add("synonym");
1662 propertyPaths
.add("synonym.name");
1663 List
<OrderHint
> orderHints
= new ArrayList
<OrderHint
>();
1664 orderHints
.add(new OrderHint("relatedFrom.titleCache", SortOrder
.ASCENDING
));
1666 List
<SynonymRelationship
> synonymRelationshipsOfParent
= dao
.getSynonyms(parentTaxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1667 List
<SynonymRelationship
> synonymRelationshipsOfTaxon
= dao
.getSynonyms(taxon
, SynonymRelationshipType
.HETEROTYPIC_SYNONYM_OF(), null, null,orderHints
,propertyPaths
);
1669 List
<TaxonRelationship
> taxonRelListParent
= null;
1670 List
<TaxonRelationship
> taxonRelListTaxon
= null;
1671 if (doWithMisappliedNames
){
1672 taxonRelListParent
= dao
.getTaxonRelationships(parentTaxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1673 taxonRelListTaxon
= dao
.getTaxonRelationships(taxon
, TaxonRelationshipType
.MISAPPLIED_NAME_FOR(), null, null, orderHints
, propertyPaths
, Direction
.relatedTo
);
1677 if (type
.equals(SynonymRelationshipType
.INFERRED_EPITHET_OF())){
1680 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1681 Synonym syn
= synonymRelationOfParent
.getSynonym();
1683 inferredEpithet
= createInferredEpithets(taxon
,
1684 zooHashMap
, taxonName
, epithetOfTaxon
,
1685 infragenericEpithetOfTaxon
,
1686 infraspecificEpithetOfTaxon
,
1687 taxonNames
, parentName
,
1691 inferredSynonyms
.add(inferredEpithet
);
1692 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1693 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1696 if (doWithMisappliedNames
){
1698 for (TaxonRelationship taxonRelationship
: taxonRelListParent
){
1699 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1701 inferredEpithet
= createInferredEpithets(taxon
,
1702 zooHashMap
, taxonName
, epithetOfTaxon
,
1703 infragenericEpithetOfTaxon
,
1704 infraspecificEpithetOfTaxon
,
1705 taxonNames
, parentName
,
1708 inferredSynonyms
.add(inferredEpithet
);
1709 zooHashMap
.put(inferredEpithet
.getName().getUuid(), (ZoologicalName
)inferredEpithet
.getName());
1710 taxonNames
.add(((ZoologicalName
)inferredEpithet
.getName()).getNameCache());
1714 if (!taxonNames
.isEmpty()){
1715 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1716 ZoologicalName name
;
1717 if (!synNotInCDM
.isEmpty()){
1718 inferredSynonymsToBeRemoved
.clear();
1720 for (Synonym syn
:inferredSynonyms
){
1721 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1722 if (!synNotInCDM
.contains(name
.getNameCache())){
1723 inferredSynonymsToBeRemoved
.add(syn
);
1727 // Remove identified Synonyms from inferredSynonyms
1728 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1729 inferredSynonyms
.remove(synonym
);
1734 }else if (type
.equals(SynonymRelationshipType
.INFERRED_GENUS_OF())){
1737 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1738 TaxonNameBase synName
;
1739 ZoologicalName inferredSynName
;
1741 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1742 inferredGenus
= createInferredGenus(taxon
,
1743 zooHashMap
, taxonName
, epithetOfTaxon
,
1744 genusOfTaxon
, taxonNames
, zooParentName
, syn
);
1746 inferredSynonyms
.add(inferredGenus
);
1747 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1748 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1753 if (doWithMisappliedNames
){
1755 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1756 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1757 inferredGenus
= createInferredGenus(taxon
, zooHashMap
, taxonName
, infraspecificEpithetOfTaxon
, genusOfTaxon
, taxonNames
, zooParentName
, misappliedName
);
1759 inferredSynonyms
.add(inferredGenus
);
1760 zooHashMap
.put(inferredGenus
.getName().getUuid(), (ZoologicalName
)inferredGenus
.getName());
1761 taxonNames
.add(( (ZoologicalName
)inferredGenus
.getName()).getNameCache());
1766 if (!taxonNames
.isEmpty()){
1767 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1768 ZoologicalName name
;
1769 if (!synNotInCDM
.isEmpty()){
1770 inferredSynonymsToBeRemoved
.clear();
1772 for (Synonym syn
:inferredSynonyms
){
1773 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1774 if (!synNotInCDM
.contains(name
.getNameCache())){
1775 inferredSynonymsToBeRemoved
.add(syn
);
1779 // Remove identified Synonyms from inferredSynonyms
1780 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1781 inferredSynonyms
.remove(synonym
);
1786 }else if (type
.equals(SynonymRelationshipType
.POTENTIAL_COMBINATION_OF())){
1788 Reference sourceReference
= null; // TODO: Determination of sourceReference is redundant
1789 ZoologicalName inferredSynName
;
1790 //for all synonyms of the parent...
1791 for (SynonymRelationship synonymRelationOfParent
:synonymRelationshipsOfParent
){
1792 TaxonNameBase synName
;
1793 Synonym synParent
= synonymRelationOfParent
.getSynonym();
1794 synName
= synParent
.getName();
1796 HibernateProxyHelper
.deproxy(synParent
);
1798 // Set the sourceReference
1799 sourceReference
= synParent
.getSec();
1801 // Determine the idInSource
1802 String idInSourceParent
= getIdInSource(synParent
);
1804 ZoologicalName parentSynZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
1805 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1806 String synParentInfragenericName
= null;
1807 String synParentSpecificEpithet
= null;
1809 if (parentSynZooName
.isInfraGeneric()){
1810 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1812 if (parentSynZooName
.isSpecies()){
1813 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1816 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
1817 synonymsGenus.put(synGenusName, idInSource);
1820 //for all synonyms of the taxon
1822 for (SynonymRelationship synonymRelationOfTaxon
:synonymRelationshipsOfTaxon
){
1824 Synonym syn
= synonymRelationOfTaxon
.getSynonym();
1825 ZoologicalName zooSynName
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1826 potentialCombination
= createPotentialCombination(idInSourceParent
, parentSynZooName
, zooSynName
,
1828 synParentInfragenericName
,
1829 synParentSpecificEpithet
, syn
, zooHashMap
);
1831 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1832 inferredSynonyms
.add(potentialCombination
);
1833 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1834 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1841 if (doWithMisappliedNames
){
1843 for (TaxonRelationship parentRelationship
: taxonRelListParent
){
1845 TaxonNameBase misappliedParentName
;
1847 Taxon misappliedParent
= parentRelationship
.getFromTaxon();
1848 misappliedParentName
= misappliedParent
.getName();
1850 HibernateProxyHelper
.deproxy(misappliedParent
);
1852 // Set the sourceReference
1853 sourceReference
= misappliedParent
.getSec();
1855 // Determine the idInSource
1856 String idInSourceParent
= getIdInSource(misappliedParent
);
1858 ZoologicalName parentSynZooName
= getZoologicalName(misappliedParentName
.getUuid(), zooHashMap
);
1859 String synParentGenus
= parentSynZooName
.getGenusOrUninomial();
1860 String synParentInfragenericName
= null;
1861 String synParentSpecificEpithet
= null;
1863 if (parentSynZooName
.isInfraGeneric()){
1864 synParentInfragenericName
= parentSynZooName
.getInfraGenericEpithet();
1866 if (parentSynZooName
.isSpecies()){
1867 synParentSpecificEpithet
= parentSynZooName
.getSpecificEpithet();
1871 for (TaxonRelationship taxonRelationship
: taxonRelListTaxon
){
1872 Taxon misappliedName
= taxonRelationship
.getFromTaxon();
1873 ZoologicalName zooMisappliedName
= getZoologicalName(misappliedName
.getName().getUuid(), zooHashMap
);
1874 potentialCombination
= createPotentialCombination(
1875 idInSourceParent
, parentSynZooName
, zooMisappliedName
,
1877 synParentInfragenericName
,
1878 synParentSpecificEpithet
, misappliedName
, zooHashMap
);
1881 taxon
.addSynonym(potentialCombination
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
1882 inferredSynonyms
.add(potentialCombination
);
1883 zooHashMap
.put(potentialCombination
.getName().getUuid(), (ZoologicalName
)potentialCombination
.getName());
1884 taxonNames
.add(( (ZoologicalName
)potentialCombination
.getName()).getNameCache());
1889 if (!taxonNames
.isEmpty()){
1890 List
<String
> synNotInCDM
= dao
.taxaByNameNotInDB(taxonNames
);
1891 ZoologicalName name
;
1892 if (!synNotInCDM
.isEmpty()){
1893 inferredSynonymsToBeRemoved
.clear();
1894 for (Synonym syn
:inferredSynonyms
){
1896 name
= (ZoologicalName
) syn
.getName();
1897 }catch (ClassCastException e
){
1898 name
= getZoologicalName(syn
.getName().getUuid(), zooHashMap
);
1900 if (!synNotInCDM
.contains(name
.getNameCache())){
1901 inferredSynonymsToBeRemoved
.add(syn
);
1904 // Remove identified Synonyms from inferredSynonyms
1905 for (Synonym synonym
: inferredSynonymsToBeRemoved
) {
1906 inferredSynonyms
.remove(synonym
);
1912 logger
.info("The synonymrelationship type is not defined.");
1913 return inferredSynonyms
;
1920 return inferredSynonyms
;
1923 private Synonym
createPotentialCombination(String idInSourceParent
,
1924 ZoologicalName parentSynZooName
, ZoologicalName zooSynName
, String synParentGenus
,
1925 String synParentInfragenericName
, String synParentSpecificEpithet
,
1926 TaxonBase syn
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
1927 Synonym potentialCombination
;
1928 Reference sourceReference
;
1929 ZoologicalName inferredSynName
;
1930 HibernateProxyHelper
.deproxy(syn
);
1932 // Set sourceReference
1933 sourceReference
= syn
.getSec();
1934 if (sourceReference
== null){
1935 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
1937 if (!parentSynZooName
.getTaxa().isEmpty()){
1938 TaxonBase taxon
= parentSynZooName
.getTaxa().iterator().next();
1940 sourceReference
= taxon
.getSec();
1943 String synTaxonSpecificEpithet
= zooSynName
.getSpecificEpithet();
1945 String synTaxonInfraSpecificName
= null;
1947 if (parentSynZooName
.isSpecies()){
1948 synTaxonInfraSpecificName
= zooSynName
.getInfraSpecificEpithet();
1951 /*if (epithetName != null && !synonymsEpithet.contains(epithetName)){
1952 synonymsEpithet.add(epithetName);
1955 //create potential combinations...
1956 inferredSynName
= ZoologicalName
.NewInstance(syn
.getName().getRank());
1958 inferredSynName
.setGenusOrUninomial(synParentGenus
);
1959 if (zooSynName
.isSpecies()){
1960 inferredSynName
.setSpecificEpithet(synTaxonSpecificEpithet
);
1961 if (parentSynZooName
.isInfraGeneric()){
1962 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1965 if (zooSynName
.isInfraSpecific()){
1966 inferredSynName
.setSpecificEpithet(synParentSpecificEpithet
);
1967 inferredSynName
.setInfraSpecificEpithet(synTaxonInfraSpecificName
);
1969 if (parentSynZooName
.isInfraGeneric()){
1970 inferredSynName
.setInfraGenericEpithet(synParentInfragenericName
);
1974 potentialCombination
= Synonym
.NewInstance(inferredSynName
, null);
1976 // Set the sourceReference
1977 potentialCombination
.setSec(sourceReference
);
1980 // Determine the idInSource
1981 String idInSourceSyn
= getIdInSource(syn
);
1983 if (idInSourceParent
!= null && idInSourceSyn
!= null) {
1984 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1985 inferredSynName
.addSource(originalSource
);
1986 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceParent
, POTENTIAL_COMBINATION_NAMESPACE
, sourceReference
, null);
1987 potentialCombination
.addSource(originalSource
);
1990 inferredSynName
.generateTitle();
1992 return potentialCombination
;
1995 private Synonym
createInferredGenus(Taxon taxon
,
1996 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
1997 String epithetOfTaxon
, String genusOfTaxon
,
1998 List
<String
> taxonNames
, ZoologicalName zooParentName
,
2001 Synonym inferredGenus
;
2002 TaxonNameBase synName
;
2003 ZoologicalName inferredSynName
;
2004 synName
=syn
.getName();
2005 HibernateProxyHelper
.deproxy(syn
);
2007 // Determine the idInSource
2008 String idInSourceSyn
= getIdInSource(syn
);
2009 String idInSourceTaxon
= getIdInSource(taxon
);
2010 // Determine the sourceReference
2011 Reference sourceReference
= syn
.getSec();
2013 //logger.warn(sourceReference.getTitleCache());
2015 synName
= syn
.getName();
2016 ZoologicalName synZooName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2017 String synSpeciesEpithetName
= synZooName
.getSpecificEpithet();
2018 /* if (synonymsEpithet != null && !synonymsEpithet.contains(synSpeciesEpithetName)){
2019 synonymsEpithet.add(synSpeciesEpithetName);
2022 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2023 //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...
2026 inferredSynName
.setGenusOrUninomial(genusOfTaxon
);
2027 if (zooParentName
.isInfraGeneric()){
2028 inferredSynName
.setInfraGenericEpithet(zooParentName
.getInfraGenericEpithet());
2031 if (taxonName
.isSpecies()){
2032 inferredSynName
.setSpecificEpithet(synSpeciesEpithetName
);
2034 if (taxonName
.isInfraSpecific()){
2035 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2036 inferredSynName
.setInfraSpecificEpithet(synZooName
.getInfraGenericEpithet());
2040 inferredGenus
= Synonym
.NewInstance(inferredSynName
, null);
2042 // Set the sourceReference
2043 inferredGenus
.setSec(sourceReference
);
2045 // Add the original source
2046 if (idInSourceSyn
!= null && idInSourceTaxon
!= null) {
2047 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2048 inferredGenus
.addSource(originalSource
);
2050 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2051 inferredSynName
.addSource(originalSource
);
2052 originalSource
= null;
2055 logger
.error("There is an idInSource missing: " + idInSourceSyn
+ " of Synonym or " + idInSourceTaxon
+ " of Taxon");
2056 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2057 inferredGenus
.addSource(originalSource
);
2059 originalSource
= IdentifiableSource
.NewInstance(idInSourceSyn
+ "; " + idInSourceTaxon
, INFERRED_GENUS_NAMESPACE
, sourceReference
, null);
2060 inferredSynName
.addSource(originalSource
);
2061 originalSource
= null;
2064 taxon
.addSynonym(inferredGenus
, SynonymRelationshipType
.INFERRED_GENUS_OF());
2066 inferredSynName
.generateTitle();
2069 return inferredGenus
;
2072 private Synonym
createInferredEpithets(Taxon taxon
,
2073 HashMap
<UUID
, ZoologicalName
> zooHashMap
, ZoologicalName taxonName
,
2074 String epithetOfTaxon
, String infragenericEpithetOfTaxon
,
2075 String infraspecificEpithetOfTaxon
, List
<String
> taxonNames
,
2076 TaxonNameBase parentName
, TaxonBase syn
) {
2078 Synonym inferredEpithet
;
2079 TaxonNameBase
<?
,?
> synName
;
2080 ZoologicalName inferredSynName
;
2081 HibernateProxyHelper
.deproxy(syn
);
2083 // Determine the idInSource
2084 String idInSourceSyn
= getIdInSource(syn
);
2085 String idInSourceTaxon
= getIdInSource(taxon
);
2086 // Determine the sourceReference
2087 Reference
<?
> sourceReference
= syn
.getSec();
2089 if (sourceReference
== null){
2090 logger
.warn("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon");
2092 System
.out
.println("The synonym has no sec reference because it is a misapplied name! Take the sec reference of taxon" + taxon
.getSec());
2093 sourceReference
= taxon
.getSec();
2096 synName
= syn
.getName();
2097 ZoologicalName zooSynName
= getZoologicalName(synName
.getUuid(), zooHashMap
);
2098 String synGenusName
= zooSynName
.getGenusOrUninomial();
2099 String synInfraGenericEpithet
= null;
2100 String synSpecificEpithet
= null;
2102 if (zooSynName
.getInfraGenericEpithet() != null){
2103 synInfraGenericEpithet
= zooSynName
.getInfraGenericEpithet();
2106 if (zooSynName
.isInfraSpecific()){
2107 synSpecificEpithet
= zooSynName
.getSpecificEpithet();
2110 /* if (synGenusName != null && !synonymsGenus.containsKey(synGenusName)){
2111 synonymsGenus.put(synGenusName, idInSource);
2114 inferredSynName
= ZoologicalName
.NewInstance(taxon
.getName().getRank());
2116 // DEBUG TODO: for subgenus or subspecies the infrageneric or infraspecific epithet should be used!!!
2117 if (epithetOfTaxon
== null && infragenericEpithetOfTaxon
== null && infraspecificEpithetOfTaxon
== null) {
2118 logger
.error("This specificEpithet is NULL" + taxon
.getTitleCache());
2120 inferredSynName
.setGenusOrUninomial(synGenusName
);
2122 if (parentName
.isInfraGeneric()){
2123 inferredSynName
.setInfraGenericEpithet(synInfraGenericEpithet
);
2125 if (taxonName
.isSpecies()){
2126 inferredSynName
.setSpecificEpithet(epithetOfTaxon
);
2127 }else if (taxonName
.isInfraSpecific()){
2128 inferredSynName
.setSpecificEpithet(synSpecificEpithet
);
2129 inferredSynName
.setInfraSpecificEpithet(infraspecificEpithetOfTaxon
);
2132 inferredEpithet
= Synonym
.NewInstance(inferredSynName
, null);
2134 // Set the sourceReference
2135 inferredEpithet
.setSec(sourceReference
);
2137 /* Add the original source
2138 if (idInSource != null) {
2139 IdentifiableSource originalSource = IdentifiableSource.NewInstance(idInSource, "InferredEpithetOf", syn.getSec(), null);
2142 Reference citation = getCitation(syn);
2143 if (citation != null) {
2144 originalSource.setCitation(citation);
2145 inferredEpithet.addSource(originalSource);
2148 String taxonId
= idInSourceTaxon
+ "; " + idInSourceSyn
;
2151 IdentifiableSource originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2153 inferredEpithet
.addSource(originalSource
);
2155 originalSource
= IdentifiableSource
.NewInstance(taxonId
, INFERRED_EPITHET_NAMESPACE
, sourceReference
, null);
2157 inferredSynName
.addSource(originalSource
);
2161 taxon
.addSynonym(inferredEpithet
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
2163 inferredSynName
.generateTitle();
2164 return inferredEpithet
;
2168 * Returns an existing ZoologicalName or extends an internal hashmap if it does not exist.
2169 * Very likely only useful for createInferredSynonyms().
2174 private ZoologicalName
getZoologicalName(UUID uuid
, HashMap
<UUID
, ZoologicalName
> zooHashMap
) {
2175 ZoologicalName taxonName
=nameDao
.findZoologicalNameByUUID(uuid
);
2176 if (taxonName
== null) {
2177 taxonName
= zooHashMap
.get(uuid
);
2183 * Returns the idInSource for a given Synonym.
2186 private String
getIdInSource(TaxonBase taxonBase
) {
2187 String idInSource
= null;
2188 Set
<IdentifiableSource
> sources
= taxonBase
.getSources();
2189 if (sources
.size() == 1) {
2190 IdentifiableSource source
= sources
.iterator().next();
2191 if (source
!= null) {
2192 idInSource
= source
.getIdInSource();
2194 } else if (sources
.size() > 1) {
2197 for (IdentifiableSource source
: sources
) {
2198 idInSource
+= source
.getIdInSource();
2199 if (count
< sources
.size()) {
2204 } else if (sources
.size() == 0){
2205 logger
.warn("No idInSource for TaxonBase " + taxonBase
.getUuid() + " - " + taxonBase
.getTitleCache());
2214 * Returns the citation for a given Synonym.
2217 private Reference
getCitation(Synonym syn
) {
2218 Reference citation
= null;
2219 Set
<IdentifiableSource
> sources
= syn
.getSources();
2220 if (sources
.size() == 1) {
2221 IdentifiableSource source
= sources
.iterator().next();
2222 if (source
!= null) {
2223 citation
= source
.getCitation();
2225 } else if (sources
.size() > 1) {
2226 logger
.warn("This Synonym has more than one source: " + syn
.getUuid() + " (" + syn
.getTitleCache() +")");
2233 public List
<Synonym
> createAllInferredSynonyms(Taxon taxon
, Classification tree
, boolean doWithMisappliedNames
){
2234 List
<Synonym
> inferredSynonyms
= new ArrayList
<Synonym
>();
2236 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_EPITHET_OF(), doWithMisappliedNames
));
2237 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.INFERRED_GENUS_OF(), doWithMisappliedNames
));
2238 inferredSynonyms
.addAll(createInferredSynonyms(taxon
, tree
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF(), doWithMisappliedNames
));
2240 return inferredSynonyms
;
2244 * @see eu.etaxonomy.cdm.api.service.ITaxonService#listClassifications(eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List)
2247 public List
<Classification
> listClassifications(TaxonBase taxonBase
, Integer limit
, Integer start
, List
<String
> propertyPaths
) {
2249 // TODO quickly implemented, create according dao !!!!
2250 Set
<TaxonNode
> nodes
= new HashSet
<TaxonNode
>();
2251 Set
<Classification
> classifications
= new HashSet
<Classification
>();
2252 List
<Classification
> list
= new ArrayList
<Classification
>();
2254 if (taxonBase
== null) {
2258 taxonBase
= load(taxonBase
.getUuid());
2260 if (taxonBase
instanceof Taxon
) {
2261 nodes
.addAll(((Taxon
)taxonBase
).getTaxonNodes());
2263 for (Taxon taxon
: ((Synonym
)taxonBase
).getAcceptedTaxa() ) {
2264 nodes
.addAll(taxon
.getTaxonNodes());
2267 for (TaxonNode node
: nodes
) {
2268 classifications
.add(node
.getClassification());
2270 list
.addAll(classifications
);