2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.api
.service
;
12 import java
.io
.IOException
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collection
;
15 import java
.util
.HashMap
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
20 import java
.util
.UUID
;
22 import org
.apache
.log4j
.Logger
;
23 import org
.apache
.lucene
.index
.CorruptIndexException
;
24 import org
.apache
.lucene
.index
.Term
;
25 import org
.apache
.lucene
.queryparser
.classic
.ParseException
;
26 import org
.apache
.lucene
.sandbox
.queries
.FuzzyLikeThisQuery
;
27 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
28 import org
.apache
.lucene
.search
.BooleanQuery
;
29 import org
.apache
.lucene
.search
.BooleanQuery
.Builder
;
30 import org
.apache
.lucene
.search
.TopDocs
;
31 import org
.apache
.lucene
.search
.WildcardQuery
;
32 import org
.hibernate
.criterion
.Criterion
;
33 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
34 import org
.springframework
.beans
.factory
.annotation
.Qualifier
;
35 import org
.springframework
.stereotype
.Service
;
36 import org
.springframework
.transaction
.annotation
.Transactional
;
38 import eu
.etaxonomy
.cdm
.api
.service
.config
.DeleteConfiguratorBase
;
39 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
40 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
41 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
42 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.AbstractPagerImpl
;
43 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
44 import eu
.etaxonomy
.cdm
.api
.service
.search
.DocumentSearchResult
;
45 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
49 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
50 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
51 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
52 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
53 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
54 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
55 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
56 import eu
.etaxonomy
.cdm
.model
.common
.ReferencedEntityBase
;
57 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
58 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
59 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementSource
;
60 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
61 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationship
;
62 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationshipType
;
63 import eu
.etaxonomy
.cdm
.model
.name
.INonViralName
;
64 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
65 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
66 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
67 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
68 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
69 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
70 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignationStatus
;
71 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
72 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
73 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
74 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
75 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
76 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
77 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IReferencedEntityDao
;
78 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ITermVocabularyDao
;
79 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.IHomotypicalGroupDao
;
80 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.INomenclaturalStatusDao
;
81 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
82 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITypeDesignationDao
;
83 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
84 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
85 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
86 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedText
;
87 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
88 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
92 @Transactional(readOnly
= true)
93 public class NameServiceImpl
extends IdentifiableServiceBase
<TaxonNameBase
,ITaxonNameDao
> implements INameService
{
94 static private final Logger logger
= Logger
.getLogger(NameServiceImpl
.class);
97 protected ITermVocabularyDao vocabularyDao
;
99 protected IOrderedTermVocabularyDao orderedVocabularyDao
;
101 @Qualifier("refEntDao")
102 protected IReferencedEntityDao
<ReferencedEntityBase
> referencedEntityDao
;
104 private INomenclaturalStatusDao nomStatusDao
;
106 private ITypeDesignationDao typeDesignationDao
;
108 private IHomotypicalGroupDao homotypicalGroupDao
;
110 private ICdmGenericDao genericDao
;
112 private ILuceneIndexToolProvider luceneIndexToolProvider
;
117 public NameServiceImpl(){
118 if (logger
.isDebugEnabled()) { logger
.debug("Load NameService Bean"); }
121 //********************* METHODS ****************************************************************//
124 * @see eu.etaxonomy.cdm.api.service.ServiceBase#delete(eu.etaxonomy.cdm.model.common.CdmBase)
127 @Transactional(readOnly
= false)
128 public DeleteResult
delete(UUID nameUUID
){
129 NameDeletionConfigurator config
= new NameDeletionConfigurator();
130 DeleteResult result
= delete(nameUUID
, config
);
135 public DeleteResult
delete(TaxonNameBase name
){
136 return delete(name
.getUuid());
140 * @see eu.etaxonomy.cdm.api.service.INameService#delete(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.api.service.NameDeletionConfigurator)
143 @Transactional(readOnly
= false)
144 public DeleteResult
delete(UUID nameUUID
, NameDeletionConfigurator config
) {
145 DeleteResult result
= new DeleteResult();
146 TaxonNameBase name
= dao
.load(nameUUID
);
154 result
= this.isDeletable(name
.getUuid(), config
);
156 result
.addException(e
);
161 //remove references to this name
162 removeNameRelationshipsByDeleteConfig(name
, config
);
164 //remove name from homotypical group
165 HomotypicalGroup homotypicalGroup
= name
.getHomotypicalGroup();
166 if (homotypicalGroup
!= null){
167 homotypicalGroup
.removeTypifiedName(name
, false);
170 //all type designation relationships are removed as they belong to the name
171 deleteTypeDesignation(name
, null);
172 // //type designations
173 // if (! name.getTypeDesignations().isEmpty()){
174 // String message = "Name can't be deleted as it has types. Remove types prior to deletion.";
175 // throw new ReferrencedObjectUndeletableException(message);
180 UUID nameUuid
= dao
.delete(name
);
183 result
.addException(e
);
193 public DeleteResult
deleteTypeDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
){
194 if(typeDesignation
!=null && typeDesignation
.getId()!=0){
195 typeDesignation
= HibernateProxyHelper
.deproxy(referencedEntityDao
.load(typeDesignation
.getUuid()), TypeDesignationBase
.class);
198 DeleteResult result
= new DeleteResult();
199 if (name
== null && typeDesignation
== null){
202 }else if (name
!= null && typeDesignation
!= null){
203 removeSingleDesignation(name
, typeDesignation
);
204 }else if (name
!= null){
205 Set
<TypeDesignationBase
> designationSet
= new HashSet
<TypeDesignationBase
>(name
.getTypeDesignations());
206 for (Object o
: designationSet
){
207 TypeDesignationBase desig
= CdmBase
.deproxy(o
, TypeDesignationBase
.class);
208 removeSingleDesignation(name
, desig
);
210 }else if (typeDesignation
!= null){
211 Set
<TaxonNameBase
> nameSet
= new HashSet
<TaxonNameBase
>(typeDesignation
.getTypifiedNames());
212 for (Object o
: nameSet
){
213 TaxonNameBase singleName
= CdmBase
.deproxy(o
, TaxonNameBase
.class);
214 removeSingleDesignation(singleName
, typeDesignation
);
217 result
.addUpdatedObject(name
);
223 public DeleteResult
deleteTypeDesignation(UUID nameUuid
, UUID typeDesignationUuid
){
224 TaxonNameBase nameBase
= load(nameUuid
);
225 TypeDesignationBase typeDesignation
= HibernateProxyHelper
.deproxy(referencedEntityDao
.load(typeDesignationUuid
), TypeDesignationBase
.class);
226 return deleteTypeDesignation(nameBase
, typeDesignation
);
231 * @param typeDesignation
233 private void removeSingleDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
) {
234 name
.removeTypeDesignation(typeDesignation
);
235 if (typeDesignation
.getTypifiedNames().isEmpty()){
236 typeDesignation
.removeType();
237 typeDesignationDao
.delete(typeDesignation
);
247 private void removeNameRelationshipsByDeleteConfig(TaxonNameBase
<?
,?
> name
, NameDeletionConfigurator config
) {
249 if (config
.isRemoveAllNameRelationships()){
250 Set
<NameRelationship
> rels
= getModifiableSet(name
.getNameRelations());
251 for (NameRelationship rel
: rels
){
252 name
.removeNameRelationship(rel
);
255 //relations to this name
256 Set
<NameRelationship
> rels
= getModifiableSet(name
.getRelationsToThisName());
257 for (NameRelationship rel
: rels
){
258 if (config
.isIgnoreHasBasionym() && NameRelationshipType
.BASIONYM().equals(rel
.getType() )){
259 name
.removeNameRelationship(rel
);
260 }else if (config
.isIgnoreHasReplacedSynonym() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
261 name
.removeNameRelationship(rel
);
264 //relations from this name
265 rels
= getModifiableSet(name
.getRelationsFromThisName());
266 for (NameRelationship rel
: rels
){
267 if (config
.isIgnoreIsBasionymFor() && NameRelationshipType
.BASIONYM().equals(rel
.getType()) ){
268 name
.removeNameRelationship(rel
);
269 }else if (config
.isIgnoreIsReplacedSynonymFor() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
270 name
.removeNameRelationship(rel
);
275 } catch (Exception e
) {
276 throw new RuntimeException(e
);
284 private Set
<NameRelationship
> getModifiableSet(Set
<NameRelationship
> relations
) {
285 Set
<NameRelationship
> rels
= new HashSet
<NameRelationship
>();
286 for (NameRelationship rel
: relations
){
292 //********************* METHODS ****************************************************************//
296 * TODO candidate for harmonization
297 * new name findByName
301 public List
<NonViralName
> getNamesByNameCache(String nameCache
){
302 boolean includeAuthors
= false;
303 List result
= dao
.findByName(includeAuthors
, nameCache
, MatchMode
.EXACT
, null, null, null, null);
309 * TODO candidate for harmonization
310 * new name saveHomotypicalGroups
315 public List
<NonViralName
> findNamesByTitleCache(String titleCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
316 List result
= dao
.findByTitle(titleCache
, matchMode
, null, null, null ,propertyPaths
);
321 * TODO candidate for harmonization
322 * new name saveHomotypicalGroups
327 public List
<NonViralName
> findNamesByNameCache(String nameCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
328 List result
= dao
.findByName(false, nameCache
, matchMode
, null, null, null ,propertyPaths
);
333 * TODO candidate for harmonization
336 public List
getNamesByName(String name
, CdmBase sessionObject
){
337 return super.findCdmObjectsByTitle(name
, sessionObject
);
341 * TODO candidate for harmonization
342 * new name saveHomotypicalGroups
345 @Transactional(readOnly
= false)
346 public Map
<UUID
, HomotypicalGroup
> saveAllHomotypicalGroups(Collection
<HomotypicalGroup
> homotypicalGroups
){
347 return homotypicalGroupDao
.saveAll(homotypicalGroups
);
351 * TODO candidate for harmonization
352 * new name saveTypeDesignations
355 @Transactional(readOnly
= false)
356 public Map
<UUID
, TypeDesignationBase
> saveTypeDesignationAll(Collection
<TypeDesignationBase
> typeDesignationCollection
){
357 return typeDesignationDao
.saveAll(typeDesignationCollection
);
361 * TODO candidate for harmonization
362 * new name saveReferencedEntities
365 @Transactional(readOnly
= false)
366 public Map
<UUID
, ReferencedEntityBase
> saveReferencedEntitiesAll(Collection
<ReferencedEntityBase
> referencedEntityCollection
){
367 return referencedEntityDao
.saveAll(referencedEntityCollection
);
371 * TODO candidate for harmonization
374 public List
<TaxonNameBase
> getAllNames(int limit
, int start
){
375 return dao
.list(limit
, start
);
379 * TODO candidate for harmonization
380 * new name getNomenclaturalStatus
383 public List
<NomenclaturalStatus
> getAllNomenclaturalStatus(int limit
, int start
){
384 return nomStatusDao
.list(limit
, start
);
388 * TODO candidate for harmonization
389 * new name getTypeDesignations
392 public List
<TypeDesignationBase
> getAllTypeDesignations(int limit
, int start
){
393 return typeDesignationDao
.getAllTypeDesignations(limit
, start
);
396 * FIXME Candidate for harmonization
397 * homotypicalGroupService.list
400 public List
<HomotypicalGroup
> getAllHomotypicalGroups(int limit
, int start
){
401 return homotypicalGroupDao
.list(limit
, start
);
405 * FIXME Candidate for harmonization
410 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
411 return dao
.getAllRelationships(limit
, start
);
418 protected void setDao(ITaxonNameDao dao
) {
423 public Pager
<HybridRelationship
> getHybridNames(INonViralName name
, HybridRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
424 Integer numberOfResults
= dao
.countHybridNames(name
, type
);
426 List
<HybridRelationship
> results
= new ArrayList
<HybridRelationship
>();
427 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
428 results
= dao
.getHybridNames(name
, type
, pageSize
, pageNumber
,orderHints
,propertyPaths
);
431 return new DefaultPagerImpl
<HybridRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
435 public List
<NameRelationship
> listNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
436 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
438 Integer numberOfResults
= dao
.countNameRelationships(name
, direction
, type
);
440 List
<NameRelationship
> results
= new ArrayList
<NameRelationship
>();
441 if (AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
442 results
= dao
.getNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
448 protected LuceneSearch
prepareFindByFuzzyNameSearch(Class
<?
extends CdmBase
> clazz
,
452 List
<Language
> languages
,
453 boolean highlightFragments
) {
454 String similarity
= Float
.toString(accuracy
);
455 String searchSuffix
= "~" + similarity
;
458 Builder finalQueryBuilder
= new Builder();
459 finalQueryBuilder
.setDisableCoord(false);
460 Builder textQueryBuilder
= new Builder();
461 textQueryBuilder
.setDisableCoord(false);
463 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
464 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
466 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
467 // luceneSearch.setSortFields(sortFields);
469 // ---- search criteria
470 luceneSearch
.setCdmTypRestriction(clazz
);
472 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
473 if(nvn
.getGenusOrUninomial() != null && !nvn
.getGenusOrUninomial().equals("")) {
474 fltq
.addTerms(nvn
.getGenusOrUninomial().toLowerCase(), "genusOrUninomial", accuracy
, 3);
476 //textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);
477 textQueryBuilder
.add(queryFactory
.newTermQuery("genusOrUninomial", "_null_", false), Occur
.MUST
);
480 if(nvn
.getInfraGenericEpithet() != null && !nvn
.getInfraGenericEpithet().equals("")){
481 fltq
.addTerms(nvn
.getInfraGenericEpithet().toLowerCase(), "infraGenericEpithet", accuracy
, 3);
483 //textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
484 textQueryBuilder
.add(queryFactory
.newTermQuery("infraGenericEpithet", "_null_", false), Occur
.MUST
);
487 if(nvn
.getSpecificEpithet() != null && !nvn
.getSpecificEpithet().equals("")){
488 fltq
.addTerms(nvn
.getSpecificEpithet().toLowerCase(), "specificEpithet", accuracy
, 3);
490 //textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
491 textQueryBuilder
.add(queryFactory
.newTermQuery("specificEpithet", "_null_", false), Occur
.MUST
);
494 if(nvn
.getInfraSpecificEpithet() != null && !nvn
.getInfraSpecificEpithet().equals("")){
495 fltq
.addTerms(nvn
.getInfraSpecificEpithet().toLowerCase(), "infraSpecificEpithet", accuracy
, 3);
497 //textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
498 textQueryBuilder
.add(queryFactory
.newTermQuery("infraSpecificEpithet", "_null_", false), Occur
.MUST
);
501 if(nvn
.getAuthorshipCache() != null && !nvn
.getAuthorshipCache().equals("")){
502 fltq
.addTerms(nvn
.getAuthorshipCache().toLowerCase(), "authorshipCache", accuracy
, 3);
504 //textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);
507 textQueryBuilder
.add(fltq
, Occur
.MUST
);
509 BooleanQuery textQuery
= textQueryBuilder
.build();
510 finalQueryBuilder
.add(textQuery
, Occur
.MUST
);
512 luceneSearch
.setQuery(finalQueryBuilder
.build());
514 if(highlightFragments
){
515 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
520 protected LuceneSearch
prepareFindByFuzzyNameCacheSearch(Class
<?
extends CdmBase
> clazz
,
524 List
<Language
> languages
,
525 boolean highlightFragments
) {
527 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
528 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
530 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
531 // luceneSearch.setSortFields(sortFields);
533 // ---- search criteria
534 luceneSearch
.setCdmTypRestriction(clazz
);
535 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
537 fltq
.addTerms(name
, "nameCache", accuracy
, 3);
539 BooleanQuery finalQuery
= new BooleanQuery(false);
541 finalQuery
.add(fltq
, Occur
.MUST
);
543 luceneSearch
.setQuery(finalQuery
);
545 if(highlightFragments
){
546 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
551 protected LuceneSearch
prepareFindByExactNameSearch(Class
<?
extends CdmBase
> clazz
,
554 List
<Language
> languages
,
555 boolean highlightFragments
) {
556 Builder textQueryBuilder
= new Builder();
558 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
559 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
561 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
562 // luceneSearch.setSortFields(sortFields);
564 // ---- search criteria
565 luceneSearch
.setCdmTypRestriction(clazz
);
567 if(name
!= null && !name
.equals("")) {
569 textQueryBuilder
.add(new WildcardQuery(new Term("nameCache", name
+ "*")), Occur
.MUST
);
571 textQueryBuilder
.add(queryFactory
.newTermQuery("nameCache", name
, false), Occur
.MUST
);
575 luceneSearch
.setQuery(textQueryBuilder
.build());
577 if(highlightFragments
){
578 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
584 public List
<SearchResult
<TaxonNameBase
>> findByNameFuzzySearch(
587 List
<Language
> languages
,
588 boolean highlightFragments
,
589 List
<String
> propertyPaths
,
590 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
592 logger
.info("Name to fuzzy search for : " + name
);
593 // parse the input name
594 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
595 INonViralName nvn
= parser
.parseFullName(name
);
596 if(name
!= null && !name
.equals("") && nvn
== null) {
597 throw new ParseException("Could not parse name " + name
);
599 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
601 // --- execute search
602 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
605 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
606 idFieldMap
.put(CdmBaseType
.NONVIRALNAME
, "id");
608 // --- initialize taxa, highlight matches ....
609 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
611 @SuppressWarnings("rawtypes")
612 List
<SearchResult
<TaxonNameBase
>> searchResults
= searchResultBuilder
.createResultSet(
613 topDocs
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
615 return searchResults
;
620 public List
<DocumentSearchResult
> findByNameFuzzySearch(
623 List
<Language
> languages
,
624 boolean highlightFragments
,
625 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
627 logger
.info("Name to fuzzy search for : " + name
);
628 // parse the input name
629 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
630 INonViralName nvn
= parser
.parseFullName(name
);
631 if(name
!= null && !name
.equals("") && nvn
== null) {
632 throw new ParseException("Could not parse name " + name
);
634 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
636 // --- execute search
637 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
639 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
641 // --- initialize taxa, highlight matches ....
642 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
644 @SuppressWarnings("rawtypes")
645 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
647 return searchResults
;
651 public List
<DocumentSearchResult
> findByFuzzyNameCacheSearch(
654 List
<Language
> languages
,
655 boolean highlightFragments
,
656 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
658 logger
.info("Name to fuzzy search for : " + name
);
660 LuceneSearch luceneSearch
= prepareFindByFuzzyNameCacheSearch(null, name
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
662 // --- execute search
663 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
664 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
666 // --- initialize taxa, highlight matches ....
667 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
669 @SuppressWarnings("rawtypes")
670 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
672 return searchResults
;
676 public List
<DocumentSearchResult
> findByNameExactSearch(
679 List
<Language
> languages
,
680 boolean highlightFragments
,
681 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
683 logger
.info("Name to exact search for : " + name
);
685 LuceneSearch luceneSearch
= prepareFindByExactNameSearch(null, name
, wildcard
, languages
, highlightFragments
);
687 // --- execute search
690 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
692 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
694 // --- initialize taxa, highlight matches ....
695 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
697 @SuppressWarnings("rawtypes")
698 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
700 return searchResults
;
704 public Pager
<NameRelationship
> pageNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
705 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
706 List
<NameRelationship
> results
= listNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
707 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
711 public List
<NameRelationship
> listFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
712 return listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
716 public Pager
<NameRelationship
> pageFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
717 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
718 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
722 public List
<NameRelationship
> listToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
723 return listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
727 public Pager
<NameRelationship
> pageToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
728 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
729 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
733 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
734 Integer pageSize
, Integer pageNumber
) {
735 return getTypeDesignations(name
, status
, pageSize
, pageNumber
, null);
739 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
740 Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
){
741 Integer numberOfResults
= dao
.countTypeDesignations(name
, status
);
743 List
<TypeDesignationBase
> results
= new ArrayList
<TypeDesignationBase
>();
744 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) {
745 results
= dao
.getTypeDesignations(name
, null, status
, pageSize
, pageNumber
, propertyPaths
);
748 return new DefaultPagerImpl
<TypeDesignationBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
752 * FIXME Candidate for harmonization
756 public Pager
<TaxonNameBase
> searchNames(String uninomial
,String infraGenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
757 List
<String
> propertyPaths
) {
758 Integer numberOfResults
= dao
.countNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
760 List
<TaxonNameBase
> results
= new ArrayList
<TaxonNameBase
>();
761 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
762 results
= dao
.searchNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
765 return new DefaultPagerImpl
<TaxonNameBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
769 public List
<UuidAndTitleCache
> getUuidAndTitleCacheOfNames(Integer limit
, String pattern
) {
770 return dao
.getUuidAndTitleCacheOfNames(limit
, pattern
);
774 public Pager
<TaxonNameBase
> findByName(Class
<?
extends TaxonNameBase
> clazz
, String queryString
, MatchMode matchmode
, List
<Criterion
> criteria
, Integer pageSize
,Integer pageNumber
, List
<OrderHint
> orderHints
,List
<String
> propertyPaths
) {
775 Long numberOfResults
= dao
.countByName(clazz
, queryString
, matchmode
, criteria
);
777 List
<TaxonNameBase
> results
= new ArrayList
<>();
778 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
779 results
= dao
.findByName(clazz
, queryString
, matchmode
, criteria
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
782 return new DefaultPagerImpl
<>(pageNumber
, numberOfResults
, pageSize
, results
);
786 public HomotypicalGroup
findHomotypicalGroup(UUID uuid
) {
787 return homotypicalGroupDao
.findByUuid(uuid
);
791 @Transactional(readOnly
= false)
792 public void updateTitleCache(Class
<?
extends TaxonNameBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonNameBase
> cacheStrategy
, IProgressMonitor monitor
) {
794 clazz
= TaxonNameBase
.class;
796 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
801 protected void setOtherCachesNull(TaxonNameBase name
) {
802 if (! name
.isProtectedNameCache()){
803 name
.setNameCache(null, false);
805 if (! name
.isProtectedAuthorshipCache()){
806 name
.setAuthorshipCache(null, false);
808 if (! name
.isProtectedFullTitleCache()){
809 name
.setFullTitleCache(null, false);
815 public List
<TaggedText
> getTaggedName(UUID uuid
) {
816 TaxonNameBase
<?
,?
> taxonNameBase
= dao
.load(uuid
);
817 List
<TaggedText
> taggedName
= taxonNameBase
.getTaggedName();
822 public DeleteResult
isDeletable(UUID nameUUID
, DeleteConfiguratorBase config
){
823 DeleteResult result
= new DeleteResult();
824 TaxonNameBase name
= this.load(nameUUID
);
825 NameDeletionConfigurator nameConfig
= null;
826 if (config
instanceof NameDeletionConfigurator
){
827 nameConfig
= (NameDeletionConfigurator
) config
;
829 result
.addException(new Exception("The delete configurator should be of the type NameDeletionConfigurator."));
834 if (!name
.getNameRelations().isEmpty() && !nameConfig
.isRemoveAllNameRelationships()){
835 HomotypicalGroup homotypicalGroup
= HibernateProxyHelper
.deproxy(name
.getHomotypicalGroup(), HomotypicalGroup
.class);
837 if (!nameConfig
.isIgnoreIsBasionymFor() && homotypicalGroup
.getBasionyms().contains(name
)){
838 result
.addException(new Exception( "Name can't be deleted as it is a basionym."));
841 if (!nameConfig
.isIgnoreHasBasionym() && (name
.getBasionyms().size()>0)){
842 result
.addException(new Exception( "Name can't be deleted as it has a basionym."));
845 Set
<NameRelationship
> relationships
= name
.getNameRelations();
846 for (NameRelationship rel
: relationships
){
847 if (!rel
.getType().equals(NameRelationshipType
.BASIONYM())){
848 result
.addException(new Exception("Name can't be deleted as it is used in name relationship(s). Remove name relationships prior to deletion."));
856 if (! name
.getTaxonBases().isEmpty()){
857 result
.addException(new Exception("Name can't be deleted as it is used in concept(s). Remove or change concept prior to deletion."));
861 //hybrid relationships
862 if (name
.isInstanceOf(NonViralName
.class)){
863 INonViralName nvn
= name
;
864 Set
<HybridRelationship
> parentHybridRelations
= nvn
.getHybridParentRelations();
865 //Hibernate.initialize(parentHybridRelations);
866 if (! parentHybridRelations
.isEmpty()){
867 result
.addException(new Exception("Name can't be deleted as it is a parent in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion."));
871 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjectsForDeletion(name
);
872 for (CdmBase referencingObject
: referencingObjects
){
873 //DerivedUnit?.storedUnder
874 if (referencingObject
.isInstanceOf(DerivedUnit
.class)){
875 String message
= "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";
876 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnit
.class).getTitleCache());
877 result
.addException(new ReferencedObjectUndeletableException(message
));
878 result
.addRelatedObject(referencingObject
);
881 //DescriptionElementSource#nameUsedInSource
882 else if (referencingObject
.isInstanceOf(DescriptionElementSource
.class)){
883 String message
= "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";
884 result
.addException(new ReferencedObjectUndeletableException(message
));
885 result
.addRelatedObject(referencingObject
);
888 //NameTypeDesignation#typeName
889 else if (referencingObject
.isInstanceOf(NameTypeDesignation
.class)){
890 NameTypeDesignation typeDesignation
= HibernateProxyHelper
.deproxy(referencingObject
, NameTypeDesignation
.class);
892 if (typeDesignation
.getTypeName().equals(name
)){
893 String message
= "Name can't be deleted as it is used as a name type in a NameTypeDesignation";
894 result
.addException(new ReferencedObjectUndeletableException(message
));
895 result
.addRelatedObject(referencingObject
);
899 //DeterminationEvent#taxonName
900 else if (referencingObject
.isInstanceOf(DeterminationEvent
.class)){
901 String message
= "Name can't be deleted as it is used as a determination event";
902 result
.addException(new ReferencedObjectUndeletableException(message
));
903 result
.addRelatedObject(referencingObject
);
908 //TODO inline references
911 if (!nameConfig
.isIgnoreIsReplacedSynonymFor() && name
.isReplacedSynonym()){
912 String message
= "Name can't be deleted as it is a replaced synonym.";
913 result
.addException(new Exception(message
));
916 if (!nameConfig
.isIgnoreHasReplacedSynonym() && (name
.getReplacedSynonyms().size()>0)){
917 String message
= "Name can't be deleted as it has a replaced synonym.";
918 result
.addException(new Exception(message
));
926 @Transactional(readOnly
= true)
927 public UpdateResult
setAsGroupsBasionym(UUID nameUuid
) {
928 TaxonNameBase name
= dao
.load(nameUuid
);
929 UpdateResult result
= new UpdateResult();
930 name
.setAsGroupsBasionym();
931 result
.addUpdatedObject(name
);
937 public List
<HashMap
<String
,String
>> getNameRecords(){
939 return dao
.getNameRecords();