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
.ParseException
;
27 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
28 import org
.apache
.lucene
.search
.BooleanQuery
;
29 import org
.apache
.lucene
.search
.FuzzyLikeThisQuery
;
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
.NameRelationship
;
64 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
65 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
66 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
67 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
68 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
69 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignationStatus
;
70 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
71 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
72 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
73 import eu
.etaxonomy
.cdm
.model
.occurrence
.DeterminationEvent
;
74 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
75 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
76 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IReferencedEntityDao
;
77 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ITermVocabularyDao
;
78 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.IHomotypicalGroupDao
;
79 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.INomenclaturalStatusDao
;
80 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
81 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITypeDesignationDao
;
82 import eu
.etaxonomy
.cdm
.persistence
.dto
.UuidAndTitleCache
;
83 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
84 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
85 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedText
;
86 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
87 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
91 @Transactional(readOnly
= true)
92 public class NameServiceImpl
extends IdentifiableServiceBase
<TaxonNameBase
,ITaxonNameDao
> implements INameService
{
93 static private final Logger logger
= Logger
.getLogger(NameServiceImpl
.class);
96 protected ITermVocabularyDao vocabularyDao
;
98 protected IOrderedTermVocabularyDao orderedVocabularyDao
;
100 @Qualifier("refEntDao")
101 protected IReferencedEntityDao
<ReferencedEntityBase
> referencedEntityDao
;
103 private INomenclaturalStatusDao nomStatusDao
;
105 private ITypeDesignationDao typeDesignationDao
;
107 private IHomotypicalGroupDao homotypicalGroupDao
;
109 private ICdmGenericDao genericDao
;
111 private ILuceneIndexToolProvider luceneIndexToolProvider
;
116 public NameServiceImpl(){
117 if (logger
.isDebugEnabled()) { logger
.debug("Load NameService Bean"); }
120 //********************* METHODS ****************************************************************//
123 * @see eu.etaxonomy.cdm.api.service.ServiceBase#delete(eu.etaxonomy.cdm.model.common.CdmBase)
126 @Transactional(readOnly
= false)
127 public DeleteResult
delete(UUID nameUUID
){
128 NameDeletionConfigurator config
= new NameDeletionConfigurator();
129 DeleteResult result
= delete(nameUUID
, config
);
134 public DeleteResult
delete(TaxonNameBase name
){
135 return delete(name
.getUuid());
139 * @see eu.etaxonomy.cdm.api.service.INameService#delete(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.api.service.NameDeletionConfigurator)
142 @Transactional(readOnly
= false)
143 public DeleteResult
delete(UUID nameUUID
, NameDeletionConfigurator config
) {
144 DeleteResult result
= new DeleteResult();
145 TaxonNameBase name
= dao
.load(nameUUID
);
153 result
= this.isDeletable(name
, config
);
155 result
.addException(e
);
160 //remove references to this name
161 removeNameRelationshipsByDeleteConfig(name
, config
);
163 //remove name from homotypical group
164 HomotypicalGroup homotypicalGroup
= name
.getHomotypicalGroup();
165 if (homotypicalGroup
!= null){
166 homotypicalGroup
.removeTypifiedName(name
, false);
169 //all type designation relationships are removed as they belong to the name
170 deleteTypeDesignation(name
, null);
171 // //type designations
172 // if (! name.getTypeDesignations().isEmpty()){
173 // String message = "Name can't be deleted as it has types. Remove types prior to deletion.";
174 // throw new ReferrencedObjectUndeletableException(message);
179 UUID nameUuid
= dao
.delete(name
);
182 result
.addException(e
);
194 * @see eu.etaxonomy.cdm.api.service.INameService#deleteTypeDesignation(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.model.name.TypeDesignationBase)
197 public void deleteTypeDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
){
198 if (name
== null && typeDesignation
== null){
200 }else if (name
!= null && typeDesignation
!= null){
201 removeSingleDesignation(name
, typeDesignation
);
202 }else if (name
!= null){
203 Set
<TypeDesignationBase
> designationSet
= new HashSet
<TypeDesignationBase
>(name
.getTypeDesignations());
204 for (Object o
: designationSet
){
205 TypeDesignationBase desig
= CdmBase
.deproxy(o
, TypeDesignationBase
.class);
206 removeSingleDesignation(name
, desig
);
208 }else if (typeDesignation
!= null){
209 Set
<TaxonNameBase
> nameSet
= new HashSet
<TaxonNameBase
>(typeDesignation
.getTypifiedNames());
210 for (Object o
: nameSet
){
211 TaxonNameBase singleName
= CdmBase
.deproxy(o
, TaxonNameBase
.class);
212 removeSingleDesignation(singleName
, typeDesignation
);
219 * @param typeDesignation
221 private void removeSingleDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
) {
222 name
.removeTypeDesignation(typeDesignation
);
223 if (typeDesignation
.getTypifiedNames().isEmpty()){
224 typeDesignation
.removeType();
225 typeDesignationDao
.delete(typeDesignation
);
235 private void removeNameRelationshipsByDeleteConfig(TaxonNameBase
<?
,?
> name
, NameDeletionConfigurator config
) {
237 if (config
.isRemoveAllNameRelationships()){
238 Set
<NameRelationship
> rels
= getModifiableSet(name
.getNameRelations());
239 for (NameRelationship rel
: rels
){
240 name
.removeNameRelationship(rel
);
243 //relations to this name
244 Set
<NameRelationship
> rels
= getModifiableSet(name
.getRelationsToThisName());
245 for (NameRelationship rel
: rels
){
246 if (config
.isIgnoreHasBasionym() && NameRelationshipType
.BASIONYM().equals(rel
.getType() )){
247 name
.removeNameRelationship(rel
);
248 }else if (config
.isIgnoreHasReplacedSynonym() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
249 name
.removeNameRelationship(rel
);
252 //relations from this name
253 rels
= getModifiableSet(name
.getRelationsFromThisName());
254 for (NameRelationship rel
: rels
){
255 if (config
.isIgnoreIsBasionymFor() && NameRelationshipType
.BASIONYM().equals(rel
.getType()) ){
256 name
.removeNameRelationship(rel
);
257 }else if (config
.isIgnoreIsReplacedSynonymFor() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
258 name
.removeNameRelationship(rel
);
263 } catch (Exception e
) {
264 throw new RuntimeException(e
);
272 private Set
<NameRelationship
> getModifiableSet(Set
<NameRelationship
> relations
) {
273 Set
<NameRelationship
> rels
= new HashSet
<NameRelationship
>();
274 for (NameRelationship rel
: relations
){
280 //********************* METHODS ****************************************************************//
283 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
284 * duplicate of findByName
288 public List
getNamesByName(String name
){
289 return super.findCdmObjectsByTitle(name
);
293 * TODO candidate for harmonization
294 * new name findByName
297 public List
<NonViralName
> getNamesByNameCache(String nameCache
){
298 List result
= dao
.findByName(nameCache
, MatchMode
.EXACT
, null, null, null, null);
304 * TODO candidate for harmonization
305 * new name saveHomotypicalGroups
310 public List
<NonViralName
> findNamesByTitleCache(String titleCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
311 List result
= dao
.findByTitle(titleCache
, matchMode
, null, null, null ,propertyPaths
);
316 * TODO candidate for harmonization
317 * new name saveHomotypicalGroups
322 public List
<NonViralName
> findNamesByNameCache(String nameCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
323 List result
= dao
.findByName(nameCache
, matchMode
, null, null, null ,propertyPaths
);
328 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
329 * Replace by load(UUID, propertyPaths)
333 public NonViralName
findNameByUuid(UUID uuid
, List
<String
> propertyPaths
){
334 return (NonViralName
)dao
.findByUuid(uuid
, null ,propertyPaths
);
338 * TODO candidate for harmonization
341 public List
getNamesByName(String name
, CdmBase sessionObject
){
342 return super.findCdmObjectsByTitle(name
, sessionObject
);
346 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
347 * duplicate of findByTitle(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths)
351 public List
findNamesByTitle(String title
){
352 return super.findCdmObjectsByTitle(title
);
356 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
357 * duplicate of findByTitle()
361 public List
findNamesByTitle(String title
, CdmBase sessionObject
){
362 return super.findCdmObjectsByTitle(title
, sessionObject
);
366 * TODO candidate for harmonization
367 * new name saveHomotypicalGroups
370 @Transactional(readOnly
= false)
371 public Map
<UUID
, HomotypicalGroup
> saveAllHomotypicalGroups(Collection
<HomotypicalGroup
> homotypicalGroups
){
372 return homotypicalGroupDao
.saveAll(homotypicalGroups
);
376 * TODO candidate for harmonization
377 * new name saveTypeDesignations
380 @Transactional(readOnly
= false)
381 public Map
<UUID
, TypeDesignationBase
> saveTypeDesignationAll(Collection
<TypeDesignationBase
> typeDesignationCollection
){
382 return typeDesignationDao
.saveAll(typeDesignationCollection
);
386 * TODO candidate for harmonization
387 * new name saveReferencedEntities
390 @Transactional(readOnly
= false)
391 public Map
<UUID
, ReferencedEntityBase
> saveReferencedEntitiesAll(Collection
<ReferencedEntityBase
> referencedEntityCollection
){
392 return referencedEntityDao
.saveAll(referencedEntityCollection
);
396 * TODO candidate for harmonization
399 public List
<TaxonNameBase
> getAllNames(int limit
, int start
){
400 return dao
.list(limit
, start
);
404 * TODO candidate for harmonization
405 * new name getNomenclaturalStatus
408 public List
<NomenclaturalStatus
> getAllNomenclaturalStatus(int limit
, int start
){
409 return nomStatusDao
.list(limit
, start
);
413 * TODO candidate for harmonization
414 * new name getTypeDesignations
417 public List
<TypeDesignationBase
> getAllTypeDesignations(int limit
, int start
){
418 return typeDesignationDao
.getAllTypeDesignations(limit
, start
);
421 * FIXME Candidate for harmonization
422 * homotypicalGroupService.list
425 public List
<HomotypicalGroup
> getAllHomotypicalGroups(int limit
, int start
){
426 return homotypicalGroupDao
.list(limit
, start
);
430 * FIXME Candidate for harmonization
435 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
436 return dao
.getAllRelationships(limit
, start
);
443 protected void setDao(ITaxonNameDao dao
) {
448 public Pager
<HybridRelationship
> getHybridNames(NonViralName name
, HybridRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
449 Integer numberOfResults
= dao
.countHybridNames(name
, type
);
451 List
<HybridRelationship
> results
= new ArrayList
<HybridRelationship
>();
452 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
453 results
= dao
.getHybridNames(name
, type
, pageSize
, pageNumber
,orderHints
,propertyPaths
);
456 return new DefaultPagerImpl
<HybridRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
460 public List
<NameRelationship
> listNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
461 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
463 Integer numberOfResults
= dao
.countNameRelationships(name
, direction
, type
);
465 List
<NameRelationship
> results
= new ArrayList
<NameRelationship
>();
466 if (AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
467 results
= dao
.getNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
473 protected LuceneSearch
prepareFindByFuzzyNameSearch(Class
<?
extends CdmBase
> clazz
,
477 List
<Language
> languages
,
478 boolean highlightFragments
) {
479 String similarity
= Float
.toString(accuracy
);
480 String searchSuffix
= "~" + similarity
;
483 BooleanQuery finalQuery
= new BooleanQuery(false);
484 BooleanQuery textQuery
= new BooleanQuery(false);
486 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
487 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
489 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
490 // luceneSearch.setSortFields(sortFields);
492 // ---- search criteria
493 luceneSearch
.setCdmTypRestriction(clazz
);
495 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
496 if(nvn
.getGenusOrUninomial() != null && !nvn
.getGenusOrUninomial().equals("")) {
497 fltq
.addTerms(nvn
.getGenusOrUninomial().toLowerCase(), "genusOrUninomial", accuracy
, 3);
499 //textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);
500 textQuery
.add(queryFactory
.newTermQuery("genusOrUninomial", "_null_", false), Occur
.MUST
);
503 if(nvn
.getInfraGenericEpithet() != null && !nvn
.getInfraGenericEpithet().equals("")){
504 fltq
.addTerms(nvn
.getInfraGenericEpithet().toLowerCase(), "infraGenericEpithet", accuracy
, 3);
506 //textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
507 textQuery
.add(queryFactory
.newTermQuery("infraGenericEpithet", "_null_", false), Occur
.MUST
);
510 if(nvn
.getSpecificEpithet() != null && !nvn
.getSpecificEpithet().equals("")){
511 fltq
.addTerms(nvn
.getSpecificEpithet().toLowerCase(), "specificEpithet", accuracy
, 3);
513 //textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
514 textQuery
.add(queryFactory
.newTermQuery("specificEpithet", "_null_", false), Occur
.MUST
);
517 if(nvn
.getInfraSpecificEpithet() != null && !nvn
.getInfraSpecificEpithet().equals("")){
518 fltq
.addTerms(nvn
.getInfraSpecificEpithet().toLowerCase(), "infraSpecificEpithet", accuracy
, 3);
520 //textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
521 textQuery
.add(queryFactory
.newTermQuery("infraSpecificEpithet", "_null_", false), Occur
.MUST
);
524 if(nvn
.getAuthorshipCache() != null && !nvn
.getAuthorshipCache().equals("")){
525 fltq
.addTerms(nvn
.getAuthorshipCache().toLowerCase(), "authorshipCache", accuracy
, 3);
527 //textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);
530 textQuery
.add(fltq
, Occur
.MUST
);
532 finalQuery
.add(textQuery
, Occur
.MUST
);
534 luceneSearch
.setQuery(finalQuery
);
536 if(highlightFragments
){
537 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
542 protected LuceneSearch
prepareFindByFuzzyNameCacheSearch(Class
<?
extends CdmBase
> clazz
,
546 List
<Language
> languages
,
547 boolean highlightFragments
) {
549 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
550 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
552 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
553 // luceneSearch.setSortFields(sortFields);
555 // ---- search criteria
556 luceneSearch
.setCdmTypRestriction(clazz
);
557 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
559 fltq
.addTerms(name
, "nameCache", accuracy
, 3);
561 BooleanQuery finalQuery
= new BooleanQuery(false);
563 finalQuery
.add(fltq
, Occur
.MUST
);
565 luceneSearch
.setQuery(finalQuery
);
567 if(highlightFragments
){
568 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
573 protected LuceneSearch
prepareFindByExactNameSearch(Class
<?
extends CdmBase
> clazz
,
576 List
<Language
> languages
,
577 boolean highlightFragments
) {
578 BooleanQuery finalQuery
= new BooleanQuery();
579 BooleanQuery textQuery
= new BooleanQuery();
581 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
582 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
584 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
585 // luceneSearch.setSortFields(sortFields);
587 // ---- search criteria
588 luceneSearch
.setCdmTypRestriction(clazz
);
590 if(name
!= null && !name
.equals("")) {
592 textQuery
.add(new WildcardQuery(new Term("nameCache", name
+ "*")), Occur
.MUST
);
594 textQuery
.add(queryFactory
.newTermQuery("nameCache", name
, false), Occur
.MUST
);
598 luceneSearch
.setQuery(textQuery
);
600 if(highlightFragments
){
601 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
607 public List
<SearchResult
<TaxonNameBase
>> findByNameFuzzySearch(
610 List
<Language
> languages
,
611 boolean highlightFragments
,
612 List
<String
> propertyPaths
,
613 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
615 logger
.info("Name to fuzzy search for : " + name
);
616 // parse the input name
617 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
618 NonViralName nvn
= parser
.parseFullName(name
);
619 if(name
!= null && !name
.equals("") && nvn
== null) {
620 throw new ParseException("Could not parse name " + name
);
622 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
624 // --- execute search
625 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
628 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
629 idFieldMap
.put(CdmBaseType
.NONVIRALNAME
, "id");
631 // --- initialize taxa, highlight matches ....
632 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
634 @SuppressWarnings("rawtypes")
635 List
<SearchResult
<TaxonNameBase
>> searchResults
= searchResultBuilder
.createResultSet(
636 topDocs
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
638 return searchResults
;
643 public List
<DocumentSearchResult
> findByNameFuzzySearch(
646 List
<Language
> languages
,
647 boolean highlightFragments
,
648 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
650 logger
.info("Name to fuzzy search for : " + name
);
651 // parse the input name
652 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
653 NonViralName nvn
= parser
.parseFullName(name
);
654 if(name
!= null && !name
.equals("") && nvn
== null) {
655 throw new ParseException("Could not parse name " + name
);
657 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
659 // --- execute search
660 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
662 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
664 // --- initialize taxa, highlight matches ....
665 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
667 @SuppressWarnings("rawtypes")
668 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
670 return searchResults
;
674 public List
<DocumentSearchResult
> findByFuzzyNameCacheSearch(
677 List
<Language
> languages
,
678 boolean highlightFragments
,
679 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
681 logger
.info("Name to fuzzy search for : " + name
);
683 LuceneSearch luceneSearch
= prepareFindByFuzzyNameCacheSearch(null, name
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
685 // --- execute search
686 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
687 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
689 // --- initialize taxa, highlight matches ....
690 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
692 @SuppressWarnings("rawtypes")
693 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
695 return searchResults
;
699 public List
<DocumentSearchResult
> findByNameExactSearch(
702 List
<Language
> languages
,
703 boolean highlightFragments
,
704 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
706 logger
.info("Name to exact search for : " + name
);
708 LuceneSearch luceneSearch
= prepareFindByExactNameSearch(null, name
, wildcard
, languages
, highlightFragments
);
710 // --- execute search
713 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
715 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
717 // --- initialize taxa, highlight matches ....
718 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
720 @SuppressWarnings("rawtypes")
721 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
723 return searchResults
;
727 public Pager
<NameRelationship
> pageNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
728 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
729 List
<NameRelationship
> results
= listNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
730 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
734 public List
<NameRelationship
> listFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
735 return listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
739 public Pager
<NameRelationship
> pageFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
740 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
741 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
745 public List
<NameRelationship
> listToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
746 return listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
750 public Pager
<NameRelationship
> pageToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
751 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
752 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
756 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
757 Integer pageSize
, Integer pageNumber
) {
758 return getTypeDesignations(name
, status
, pageSize
, pageNumber
, null);
762 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
763 Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
){
764 Integer numberOfResults
= dao
.countTypeDesignations(name
, status
);
766 List
<TypeDesignationBase
> results
= new ArrayList
<TypeDesignationBase
>();
767 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) {
768 results
= dao
.getTypeDesignations(name
, null, status
, pageSize
, pageNumber
, propertyPaths
);
771 return new DefaultPagerImpl
<TypeDesignationBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
775 * FIXME Candidate for harmonization
779 public Pager
<TaxonNameBase
> searchNames(String uninomial
,String infraGenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
780 List
<String
> propertyPaths
) {
781 Integer numberOfResults
= dao
.countNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
783 List
<TaxonNameBase
> results
= new ArrayList
<TaxonNameBase
>();
784 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
785 results
= dao
.searchNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
788 return new DefaultPagerImpl
<TaxonNameBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
792 public List
<UuidAndTitleCache
> getUuidAndTitleCacheOfNames() {
793 return dao
.getUuidAndTitleCacheOfNames();
797 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
) {
798 Integer numberOfResults
= dao
.countByName(clazz
, queryString
, matchmode
, criteria
);
800 List
<TaxonNameBase
> results
= new ArrayList
<TaxonNameBase
>();
801 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
802 results
= dao
.findByName(clazz
, queryString
, matchmode
, criteria
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
805 return new DefaultPagerImpl
<TaxonNameBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
809 public HomotypicalGroup
findHomotypicalGroup(UUID uuid
) {
810 return homotypicalGroupDao
.findByUuid(uuid
);
814 @Transactional(readOnly
= false)
815 public void updateTitleCache(Class
<?
extends TaxonNameBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonNameBase
> cacheStrategy
, IProgressMonitor monitor
) {
817 clazz
= TaxonNameBase
.class;
819 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
824 protected void setOtherCachesNull(TaxonNameBase name
) {
825 if (name
.isInstanceOf(NonViralName
.class)){
826 NonViralName
<?
> nvn
= CdmBase
.deproxy(name
, NonViralName
.class);
827 if (! nvn
.isProtectedNameCache()){
828 nvn
.setNameCache(null, false);
830 if (! nvn
.isProtectedAuthorshipCache()){
831 nvn
.setAuthorshipCache(null, false);
833 if (! nvn
.isProtectedFullTitleCache()){
834 nvn
.setFullTitleCache(null, false);
840 public List
<TaggedText
> getTaggedName(UUID uuid
) {
841 TaxonNameBase
<?
,?
> taxonNameBase
= dao
.load(uuid
);
842 List
<TaggedText
> taggedName
= taxonNameBase
.getTaggedName();
847 public DeleteResult
isDeletable(TaxonNameBase name
, DeleteConfiguratorBase config
){
848 DeleteResult result
= new DeleteResult();
849 //name = this.load(name.getUuid());
850 NameDeletionConfigurator nameConfig
= null;
851 if (config
instanceof NameDeletionConfigurator
){
852 nameConfig
= (NameDeletionConfigurator
) config
;
854 result
.addException(new Exception("The delete configurator should be of the type NameDeletionConfigurator."));
859 if (!name
.getNameRelations().isEmpty() && !nameConfig
.isRemoveAllNameRelationships()){
860 HomotypicalGroup homotypicalGroup
= HibernateProxyHelper
.deproxy(name
.getHomotypicalGroup(), HomotypicalGroup
.class);
862 if (!nameConfig
.isIgnoreIsBasionymFor() && homotypicalGroup
.getBasionyms().contains(name
)){
863 result
.addException(new Exception( "Name can't be deleted as it is a basionym."));
866 if (!nameConfig
.isIgnoreHasBasionym() && (name
.getBasionyms().size()>0)){
867 result
.addException(new Exception( "Name can't be deleted as it has a basionym."));
870 Set
<NameRelationship
> relationships
= name
.getNameRelations();
871 for (NameRelationship rel
: relationships
){
872 if (!rel
.getType().equals(NameRelationshipType
.BASIONYM())){
873 result
.addException(new Exception("Name can't be deleted as it is used in name relationship(s). Remove name relationships prior to deletion."));
881 if (! name
.getTaxonBases().isEmpty()){
882 result
.addException(new Exception("Name can't be deleted as it is used in concept(s). Remove or change concept prior to deletion."));
886 //hybrid relationships
887 if (name
.isInstanceOf(NonViralName
.class)){
888 NonViralName nvn
= CdmBase
.deproxy(name
, NonViralName
.class);
889 if (! nvn
.getHybridParentRelations().isEmpty()){
890 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."));
894 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjectsForDeletion(name
);
895 for (CdmBase referencingObject
: referencingObjects
){
896 //DerivedUnit?.storedUnder
897 if (referencingObject
.isInstanceOf(DerivedUnit
.class)){
898 String message
= "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";
899 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnit
.class).getTitleCache());
900 result
.addException(new ReferencedObjectUndeletableException(message
));
901 result
.addRelatedObject(referencingObject
);
904 //DescriptionElementSource#nameUsedInSource
905 else if (referencingObject
.isInstanceOf(DescriptionElementSource
.class)){
906 String message
= "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";
907 result
.addException(new ReferencedObjectUndeletableException(message
));
908 result
.addRelatedObject(referencingObject
);
911 //NameTypeDesignation#typeName
912 else if (referencingObject
.isInstanceOf(NameTypeDesignation
.class)){
913 String message
= "Name can't be deleted as it is used as a name type in a NameTypeDesignation";
914 result
.addException(new ReferencedObjectUndeletableException(message
));
915 result
.addRelatedObject(referencingObject
);
918 //DeterminationEvent#taxonName
919 else if (referencingObject
.isInstanceOf(DeterminationEvent
.class)){
920 String message
= "Name can't be deleted as it is used as a determination event";
921 result
.addException(new ReferencedObjectUndeletableException(message
));
922 result
.addRelatedObject(referencingObject
);
927 //TODO inline references
930 if (!nameConfig
.isIgnoreIsReplacedSynonymFor() && name
.isReplacedSynonym()){
931 String message
= "Name can't be deleted as it is a replaced synonym.";
932 result
.addException(new Exception(message
));
935 if (!nameConfig
.isIgnoreHasReplacedSynonym() && (name
.getReplacedSynonyms().size()>0)){
936 String message
= "Name can't be deleted as it has a replaced synonym.";
937 result
.addException(new Exception(message
));
945 @Transactional(readOnly
= true)
946 public UpdateResult
setAsGroupsBasionym(UUID nameUuid
) {
947 TaxonNameBase name
= dao
.load(nameUuid
);
948 UpdateResult result
= new UpdateResult();
949 name
.setAsGroupsBasionym();
950 result
.addUpdatedObject(name
);
956 public List
<HashMap
<String
,String
>> getNameRecords(){
958 return dao
.getNameRecords();