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
.Collection
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
21 import java
.util
.UUID
;
23 import org
.apache
.log4j
.Logger
;
24 import org
.apache
.lucene
.index
.CorruptIndexException
;
25 import org
.apache
.lucene
.index
.Term
;
26 import org
.apache
.lucene
.queryparser
.classic
.ParseException
;
27 import org
.apache
.lucene
.sandbox
.queries
.FuzzyLikeThisQuery
;
28 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
29 import org
.apache
.lucene
.search
.BooleanQuery
;
30 import org
.apache
.lucene
.search
.BooleanQuery
.Builder
;
31 import org
.apache
.lucene
.search
.TopDocs
;
32 import org
.apache
.lucene
.search
.WildcardQuery
;
33 import org
.hibernate
.criterion
.Criterion
;
34 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
35 import org
.springframework
.beans
.factory
.annotation
.Qualifier
;
36 import org
.springframework
.stereotype
.Service
;
37 import org
.springframework
.transaction
.annotation
.Transactional
;
39 import eu
.etaxonomy
.cdm
.api
.service
.config
.DeleteConfiguratorBase
;
40 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
41 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
42 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
43 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.AbstractPagerImpl
;
44 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
45 import eu
.etaxonomy
.cdm
.api
.service
.search
.DocumentSearchResult
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
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
.common
.monitor
.IProgressMonitor
;
53 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
54 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
55 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
56 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
57 import eu
.etaxonomy
.cdm
.model
.common
.ReferencedEntityBase
;
58 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
59 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
60 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementSource
;
61 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
62 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationship
;
63 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationshipType
;
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
, 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
);
195 * @see eu.etaxonomy.cdm.api.service.INameService#deleteTypeDesignation(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.model.name.TypeDesignationBase)
198 public void deleteTypeDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
){
199 if (name
== null && typeDesignation
== null){
201 }else if (name
!= null && typeDesignation
!= null){
202 removeSingleDesignation(name
, typeDesignation
);
203 }else if (name
!= null){
204 Set
<TypeDesignationBase
> designationSet
= new HashSet
<TypeDesignationBase
>(name
.getTypeDesignations());
205 for (Object o
: designationSet
){
206 TypeDesignationBase desig
= CdmBase
.deproxy(o
, TypeDesignationBase
.class);
207 removeSingleDesignation(name
, desig
);
209 }else if (typeDesignation
!= null){
210 Set
<TaxonNameBase
> nameSet
= new HashSet
<TaxonNameBase
>(typeDesignation
.getTypifiedNames());
211 for (Object o
: nameSet
){
212 TaxonNameBase singleName
= CdmBase
.deproxy(o
, TaxonNameBase
.class);
213 removeSingleDesignation(singleName
, typeDesignation
);
220 * @param typeDesignation
222 private void removeSingleDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
) {
223 name
.removeTypeDesignation(typeDesignation
);
224 if (typeDesignation
.getTypifiedNames().isEmpty()){
225 typeDesignation
.removeType();
226 typeDesignationDao
.delete(typeDesignation
);
236 private void removeNameRelationshipsByDeleteConfig(TaxonNameBase
<?
,?
> name
, NameDeletionConfigurator config
) {
238 if (config
.isRemoveAllNameRelationships()){
239 Set
<NameRelationship
> rels
= getModifiableSet(name
.getNameRelations());
240 for (NameRelationship rel
: rels
){
241 name
.removeNameRelationship(rel
);
244 //relations to this name
245 Set
<NameRelationship
> rels
= getModifiableSet(name
.getRelationsToThisName());
246 for (NameRelationship rel
: rels
){
247 if (config
.isIgnoreHasBasionym() && NameRelationshipType
.BASIONYM().equals(rel
.getType() )){
248 name
.removeNameRelationship(rel
);
249 }else if (config
.isIgnoreHasReplacedSynonym() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
250 name
.removeNameRelationship(rel
);
253 //relations from this name
254 rels
= getModifiableSet(name
.getRelationsFromThisName());
255 for (NameRelationship rel
: rels
){
256 if (config
.isIgnoreIsBasionymFor() && NameRelationshipType
.BASIONYM().equals(rel
.getType()) ){
257 name
.removeNameRelationship(rel
);
258 }else if (config
.isIgnoreIsReplacedSynonymFor() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
259 name
.removeNameRelationship(rel
);
264 } catch (Exception e
) {
265 throw new RuntimeException(e
);
273 private Set
<NameRelationship
> getModifiableSet(Set
<NameRelationship
> relations
) {
274 Set
<NameRelationship
> rels
= new HashSet
<NameRelationship
>();
275 for (NameRelationship rel
: relations
){
281 //********************* METHODS ****************************************************************//
284 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
285 * duplicate of findByName
289 public List
getNamesByName(String name
){
290 return super.findCdmObjectsByTitle(name
);
294 * TODO candidate for harmonization
295 * new name findByName
298 public List
<NonViralName
> getNamesByNameCache(String nameCache
){
299 List result
= dao
.findByName(nameCache
, MatchMode
.EXACT
, null, null, null, null);
305 * TODO candidate for harmonization
306 * new name saveHomotypicalGroups
311 public List
<NonViralName
> findNamesByTitleCache(String titleCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
312 List result
= dao
.findByTitle(titleCache
, matchMode
, null, null, null ,propertyPaths
);
317 * TODO candidate for harmonization
318 * new name saveHomotypicalGroups
323 public List
<NonViralName
> findNamesByNameCache(String nameCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
324 List result
= dao
.findByName(nameCache
, matchMode
, null, null, null ,propertyPaths
);
329 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
330 * Replace by load(UUID, propertyPaths)
334 public NonViralName
findNameByUuid(UUID uuid
, List
<String
> propertyPaths
){
335 return (NonViralName
)dao
.findByUuid(uuid
, null ,propertyPaths
);
339 * TODO candidate for harmonization
342 public List
getNamesByName(String name
, CdmBase sessionObject
){
343 return super.findCdmObjectsByTitle(name
, sessionObject
);
347 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
348 * duplicate of findByTitle(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths)
352 public List
findNamesByTitle(String title
){
353 return super.findCdmObjectsByTitle(title
);
357 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
358 * duplicate of findByTitle()
362 public List
findNamesByTitle(String title
, CdmBase sessionObject
){
363 return super.findCdmObjectsByTitle(title
, sessionObject
);
367 * TODO candidate for harmonization
368 * new name saveHomotypicalGroups
371 @Transactional(readOnly
= false)
372 public Map
<UUID
, HomotypicalGroup
> saveAllHomotypicalGroups(Collection
<HomotypicalGroup
> homotypicalGroups
){
373 return homotypicalGroupDao
.saveAll(homotypicalGroups
);
377 * TODO candidate for harmonization
378 * new name saveTypeDesignations
381 @Transactional(readOnly
= false)
382 public Map
<UUID
, TypeDesignationBase
> saveTypeDesignationAll(Collection
<TypeDesignationBase
> typeDesignationCollection
){
383 return typeDesignationDao
.saveAll(typeDesignationCollection
);
387 * TODO candidate for harmonization
388 * new name saveReferencedEntities
391 @Transactional(readOnly
= false)
392 public Map
<UUID
, ReferencedEntityBase
> saveReferencedEntitiesAll(Collection
<ReferencedEntityBase
> referencedEntityCollection
){
393 return referencedEntityDao
.saveAll(referencedEntityCollection
);
397 * TODO candidate for harmonization
400 public List
<TaxonNameBase
> getAllNames(int limit
, int start
){
401 return dao
.list(limit
, start
);
405 * TODO candidate for harmonization
406 * new name getNomenclaturalStatus
409 public List
<NomenclaturalStatus
> getAllNomenclaturalStatus(int limit
, int start
){
410 return nomStatusDao
.list(limit
, start
);
414 * TODO candidate for harmonization
415 * new name getTypeDesignations
418 public List
<TypeDesignationBase
> getAllTypeDesignations(int limit
, int start
){
419 return typeDesignationDao
.getAllTypeDesignations(limit
, start
);
422 * FIXME Candidate for harmonization
423 * homotypicalGroupService.list
426 public List
<HomotypicalGroup
> getAllHomotypicalGroups(int limit
, int start
){
427 return homotypicalGroupDao
.list(limit
, start
);
431 * FIXME Candidate for harmonization
436 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
437 return dao
.getAllRelationships(limit
, start
);
444 protected void setDao(ITaxonNameDao dao
) {
449 public Pager
<HybridRelationship
> getHybridNames(NonViralName name
, HybridRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
450 Integer numberOfResults
= dao
.countHybridNames(name
, type
);
452 List
<HybridRelationship
> results
= new ArrayList
<HybridRelationship
>();
453 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
454 results
= dao
.getHybridNames(name
, type
, pageSize
, pageNumber
,orderHints
,propertyPaths
);
457 return new DefaultPagerImpl
<HybridRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
461 public List
<NameRelationship
> listNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
462 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
464 Integer numberOfResults
= dao
.countNameRelationships(name
, direction
, type
);
466 List
<NameRelationship
> results
= new ArrayList
<NameRelationship
>();
467 if (AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
468 results
= dao
.getNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
474 protected LuceneSearch
prepareFindByFuzzyNameSearch(Class
<?
extends CdmBase
> clazz
,
478 List
<Language
> languages
,
479 boolean highlightFragments
) {
480 String similarity
= Float
.toString(accuracy
);
481 String searchSuffix
= "~" + similarity
;
484 Builder finalQueryBuilder
= new Builder();
485 finalQueryBuilder
.setDisableCoord(false);
486 Builder textQueryBuilder
= new Builder();
487 textQueryBuilder
.setDisableCoord(false);
489 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
490 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
492 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
493 // luceneSearch.setSortFields(sortFields);
495 // ---- search criteria
496 luceneSearch
.setCdmTypRestriction(clazz
);
498 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
499 if(nvn
.getGenusOrUninomial() != null && !nvn
.getGenusOrUninomial().equals("")) {
500 fltq
.addTerms(nvn
.getGenusOrUninomial().toLowerCase(), "genusOrUninomial", accuracy
, 3);
502 //textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);
503 textQueryBuilder
.add(queryFactory
.newTermQuery("genusOrUninomial", "_null_", false), Occur
.MUST
);
506 if(nvn
.getInfraGenericEpithet() != null && !nvn
.getInfraGenericEpithet().equals("")){
507 fltq
.addTerms(nvn
.getInfraGenericEpithet().toLowerCase(), "infraGenericEpithet", accuracy
, 3);
509 //textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
510 textQueryBuilder
.add(queryFactory
.newTermQuery("infraGenericEpithet", "_null_", false), Occur
.MUST
);
513 if(nvn
.getSpecificEpithet() != null && !nvn
.getSpecificEpithet().equals("")){
514 fltq
.addTerms(nvn
.getSpecificEpithet().toLowerCase(), "specificEpithet", accuracy
, 3);
516 //textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
517 textQueryBuilder
.add(queryFactory
.newTermQuery("specificEpithet", "_null_", false), Occur
.MUST
);
520 if(nvn
.getInfraSpecificEpithet() != null && !nvn
.getInfraSpecificEpithet().equals("")){
521 fltq
.addTerms(nvn
.getInfraSpecificEpithet().toLowerCase(), "infraSpecificEpithet", accuracy
, 3);
523 //textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
524 textQueryBuilder
.add(queryFactory
.newTermQuery("infraSpecificEpithet", "_null_", false), Occur
.MUST
);
527 if(nvn
.getAuthorshipCache() != null && !nvn
.getAuthorshipCache().equals("")){
528 fltq
.addTerms(nvn
.getAuthorshipCache().toLowerCase(), "authorshipCache", accuracy
, 3);
530 //textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);
533 textQueryBuilder
.add(fltq
, Occur
.MUST
);
535 BooleanQuery textQuery
= textQueryBuilder
.build();
536 finalQueryBuilder
.add(textQuery
, Occur
.MUST
);
538 luceneSearch
.setQuery(finalQueryBuilder
.build());
540 if(highlightFragments
){
541 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
546 protected LuceneSearch
prepareFindByFuzzyNameCacheSearch(Class
<?
extends CdmBase
> clazz
,
550 List
<Language
> languages
,
551 boolean highlightFragments
) {
553 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
554 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
556 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
557 // luceneSearch.setSortFields(sortFields);
559 // ---- search criteria
560 luceneSearch
.setCdmTypRestriction(clazz
);
561 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
563 fltq
.addTerms(name
, "nameCache", accuracy
, 3);
565 BooleanQuery finalQuery
= new BooleanQuery(false);
567 finalQuery
.add(fltq
, Occur
.MUST
);
569 luceneSearch
.setQuery(finalQuery
);
571 if(highlightFragments
){
572 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
577 protected LuceneSearch
prepareFindByExactNameSearch(Class
<?
extends CdmBase
> clazz
,
580 List
<Language
> languages
,
581 boolean highlightFragments
) {
582 Builder textQueryBuilder
= new Builder();
584 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
585 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
587 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
588 // luceneSearch.setSortFields(sortFields);
590 // ---- search criteria
591 luceneSearch
.setCdmTypRestriction(clazz
);
593 if(name
!= null && !name
.equals("")) {
595 textQueryBuilder
.add(new WildcardQuery(new Term("nameCache", name
+ "*")), Occur
.MUST
);
597 textQueryBuilder
.add(queryFactory
.newTermQuery("nameCache", name
, false), Occur
.MUST
);
601 luceneSearch
.setQuery(textQueryBuilder
.build());
603 if(highlightFragments
){
604 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
610 public List
<SearchResult
<TaxonNameBase
>> findByNameFuzzySearch(
613 List
<Language
> languages
,
614 boolean highlightFragments
,
615 List
<String
> propertyPaths
,
616 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
618 logger
.info("Name to fuzzy search for : " + name
);
619 // parse the input name
620 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
621 NonViralName nvn
= parser
.parseFullName(name
);
622 if(name
!= null && !name
.equals("") && nvn
== null) {
623 throw new ParseException("Could not parse name " + name
);
625 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
627 // --- execute search
628 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
631 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
632 idFieldMap
.put(CdmBaseType
.NONVIRALNAME
, "id");
634 // --- initialize taxa, highlight matches ....
635 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
637 @SuppressWarnings("rawtypes")
638 List
<SearchResult
<TaxonNameBase
>> searchResults
= searchResultBuilder
.createResultSet(
639 topDocs
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
641 return searchResults
;
646 public List
<DocumentSearchResult
> findByNameFuzzySearch(
649 List
<Language
> languages
,
650 boolean highlightFragments
,
651 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
653 logger
.info("Name to fuzzy search for : " + name
);
654 // parse the input name
655 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
656 NonViralName nvn
= parser
.parseFullName(name
);
657 if(name
!= null && !name
.equals("") && nvn
== null) {
658 throw new ParseException("Could not parse name " + name
);
660 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
662 // --- execute search
663 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
665 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
667 // --- initialize taxa, highlight matches ....
668 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
670 @SuppressWarnings("rawtypes")
671 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
673 return searchResults
;
677 public List
<DocumentSearchResult
> findByFuzzyNameCacheSearch(
680 List
<Language
> languages
,
681 boolean highlightFragments
,
682 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
684 logger
.info("Name to fuzzy search for : " + name
);
686 LuceneSearch luceneSearch
= prepareFindByFuzzyNameCacheSearch(null, name
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
688 // --- execute search
689 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
690 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
692 // --- initialize taxa, highlight matches ....
693 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
695 @SuppressWarnings("rawtypes")
696 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
698 return searchResults
;
702 public List
<DocumentSearchResult
> findByNameExactSearch(
705 List
<Language
> languages
,
706 boolean highlightFragments
,
707 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
709 logger
.info("Name to exact search for : " + name
);
711 LuceneSearch luceneSearch
= prepareFindByExactNameSearch(null, name
, wildcard
, languages
, highlightFragments
);
713 // --- execute search
716 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
718 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
720 // --- initialize taxa, highlight matches ....
721 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
723 @SuppressWarnings("rawtypes")
724 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
726 return searchResults
;
730 public Pager
<NameRelationship
> pageNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
731 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
732 List
<NameRelationship
> results
= listNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
733 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
737 public List
<NameRelationship
> listFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
738 return listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
742 public Pager
<NameRelationship
> pageFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
743 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
744 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
748 public List
<NameRelationship
> listToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
749 return listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
753 public Pager
<NameRelationship
> pageToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
754 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
755 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
759 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
760 Integer pageSize
, Integer pageNumber
) {
761 return getTypeDesignations(name
, status
, pageSize
, pageNumber
, null);
765 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
766 Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
){
767 Integer numberOfResults
= dao
.countTypeDesignations(name
, status
);
769 List
<TypeDesignationBase
> results
= new ArrayList
<TypeDesignationBase
>();
770 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) {
771 results
= dao
.getTypeDesignations(name
, null, status
, pageSize
, pageNumber
, propertyPaths
);
774 return new DefaultPagerImpl
<TypeDesignationBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
778 * FIXME Candidate for harmonization
782 public Pager
<TaxonNameBase
> searchNames(String uninomial
,String infraGenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
783 List
<String
> propertyPaths
) {
784 Integer numberOfResults
= dao
.countNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
786 List
<TaxonNameBase
> results
= new ArrayList
<TaxonNameBase
>();
787 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
788 results
= dao
.searchNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
791 return new DefaultPagerImpl
<TaxonNameBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
795 public List
<UuidAndTitleCache
> getUuidAndTitleCacheOfNames() {
796 return dao
.getUuidAndTitleCacheOfNames();
800 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
) {
801 Integer numberOfResults
= dao
.countByName(clazz
, queryString
, matchmode
, criteria
);
803 List
<TaxonNameBase
> results
= new ArrayList
<TaxonNameBase
>();
804 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
805 results
= dao
.findByName(clazz
, queryString
, matchmode
, criteria
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
808 return new DefaultPagerImpl
<TaxonNameBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
812 public HomotypicalGroup
findHomotypicalGroup(UUID uuid
) {
813 return homotypicalGroupDao
.findByUuid(uuid
);
817 @Transactional(readOnly
= false)
818 public void updateTitleCache(Class
<?
extends TaxonNameBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonNameBase
> cacheStrategy
, IProgressMonitor monitor
) {
820 clazz
= TaxonNameBase
.class;
822 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
827 protected void setOtherCachesNull(TaxonNameBase name
) {
828 if (name
.isInstanceOf(NonViralName
.class)){
829 NonViralName
<?
> nvn
= CdmBase
.deproxy(name
, NonViralName
.class);
830 if (! nvn
.isProtectedNameCache()){
831 nvn
.setNameCache(null, false);
833 if (! nvn
.isProtectedAuthorshipCache()){
834 nvn
.setAuthorshipCache(null, false);
836 if (! nvn
.isProtectedFullTitleCache()){
837 nvn
.setFullTitleCache(null, false);
843 public List
<TaggedText
> getTaggedName(UUID uuid
) {
844 TaxonNameBase
<?
,?
> taxonNameBase
= dao
.load(uuid
);
845 List
<TaggedText
> taggedName
= taxonNameBase
.getTaggedName();
850 public DeleteResult
isDeletable(TaxonNameBase name
, DeleteConfiguratorBase config
){
851 DeleteResult result
= new DeleteResult();
852 //name = this.load(name.getUuid());
853 NameDeletionConfigurator nameConfig
= null;
854 if (config
instanceof NameDeletionConfigurator
){
855 nameConfig
= (NameDeletionConfigurator
) config
;
857 result
.addException(new Exception("The delete configurator should be of the type NameDeletionConfigurator."));
862 if (!name
.getNameRelations().isEmpty() && !nameConfig
.isRemoveAllNameRelationships()){
863 HomotypicalGroup homotypicalGroup
= HibernateProxyHelper
.deproxy(name
.getHomotypicalGroup(), HomotypicalGroup
.class);
865 if (!nameConfig
.isIgnoreIsBasionymFor() && homotypicalGroup
.getBasionyms().contains(name
)){
866 result
.addException(new Exception( "Name can't be deleted as it is a basionym."));
869 if (!nameConfig
.isIgnoreHasBasionym() && (name
.getBasionyms().size()>0)){
870 result
.addException(new Exception( "Name can't be deleted as it has a basionym."));
873 Set
<NameRelationship
> relationships
= name
.getNameRelations();
874 for (NameRelationship rel
: relationships
){
875 if (!rel
.getType().equals(NameRelationshipType
.BASIONYM())){
876 result
.addException(new Exception("Name can't be deleted as it is used in name relationship(s). Remove name relationships prior to deletion."));
884 if (! name
.getTaxonBases().isEmpty()){
885 result
.addException(new Exception("Name can't be deleted as it is used in concept(s). Remove or change concept prior to deletion."));
889 //hybrid relationships
890 if (name
.isInstanceOf(NonViralName
.class)){
891 NonViralName nvn
= CdmBase
.deproxy(name
, NonViralName
.class);
892 if (! nvn
.getHybridParentRelations().isEmpty()){
893 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."));
897 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjectsForDeletion(name
);
898 for (CdmBase referencingObject
: referencingObjects
){
899 //DerivedUnit?.storedUnder
900 if (referencingObject
.isInstanceOf(DerivedUnit
.class)){
901 String message
= "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";
902 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnit
.class).getTitleCache());
903 result
.addException(new ReferencedObjectUndeletableException(message
));
904 result
.addRelatedObject(referencingObject
);
907 //DescriptionElementSource#nameUsedInSource
908 else if (referencingObject
.isInstanceOf(DescriptionElementSource
.class)){
909 String message
= "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";
910 result
.addException(new ReferencedObjectUndeletableException(message
));
911 result
.addRelatedObject(referencingObject
);
914 //NameTypeDesignation#typeName
915 else if (referencingObject
.isInstanceOf(NameTypeDesignation
.class)){
916 String message
= "Name can't be deleted as it is used as a name type in a NameTypeDesignation";
917 result
.addException(new ReferencedObjectUndeletableException(message
));
918 result
.addRelatedObject(referencingObject
);
921 //DeterminationEvent#taxonName
922 else if (referencingObject
.isInstanceOf(DeterminationEvent
.class)){
923 String message
= "Name can't be deleted as it is used as a determination event";
924 result
.addException(new ReferencedObjectUndeletableException(message
));
925 result
.addRelatedObject(referencingObject
);
930 //TODO inline references
933 if (!nameConfig
.isIgnoreIsReplacedSynonymFor() && name
.isReplacedSynonym()){
934 String message
= "Name can't be deleted as it is a replaced synonym.";
935 result
.addException(new Exception(message
));
938 if (!nameConfig
.isIgnoreHasReplacedSynonym() && (name
.getReplacedSynonyms().size()>0)){
939 String message
= "Name can't be deleted as it has a replaced synonym.";
940 result
.addException(new Exception(message
));
948 @Transactional(readOnly
= true)
949 public UpdateResult
setAsGroupsBasionym(UUID nameUuid
) {
950 TaxonNameBase name
= dao
.load(nameUuid
);
951 UpdateResult result
= new UpdateResult();
952 name
.setAsGroupsBasionym();
953 result
.addUpdatedObject(name
);
959 public List
<HashMap
<String
,String
>> getNameRecords(){
961 return dao
.getNameRecords();