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
.Iterator
;
19 import java
.util
.List
;
22 import java
.util
.UUID
;
24 import org
.apache
.log4j
.Logger
;
25 import org
.apache
.lucene
.index
.CorruptIndexException
;
26 import org
.apache
.lucene
.index
.Term
;
27 import org
.apache
.lucene
.queryParser
.ParseException
;
28 import org
.apache
.lucene
.search
.BooleanClause
.Occur
;
29 import org
.apache
.lucene
.search
.BooleanQuery
;
30 import org
.apache
.lucene
.search
.FuzzyLikeThisQuery
;
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
.dao
.DataAccessException
;
37 import org
.springframework
.stereotype
.Service
;
38 import org
.springframework
.transaction
.annotation
.Transactional
;
40 import eu
.etaxonomy
.cdm
.api
.service
.config
.DeleteConfiguratorBase
;
41 import eu
.etaxonomy
.cdm
.api
.service
.config
.NameDeletionConfigurator
;
42 import eu
.etaxonomy
.cdm
.api
.service
.exception
.ReferencedObjectUndeletableException
;
43 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
44 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.AbstractPagerImpl
;
45 import eu
.etaxonomy
.cdm
.api
.service
.pager
.impl
.DefaultPagerImpl
;
46 import eu
.etaxonomy
.cdm
.api
.service
.search
.DocumentSearchResult
;
47 import eu
.etaxonomy
.cdm
.api
.service
.search
.ILuceneIndexToolProvider
;
48 import eu
.etaxonomy
.cdm
.api
.service
.search
.ISearchResultBuilder
;
49 import eu
.etaxonomy
.cdm
.api
.service
.search
.LuceneSearch
;
50 import eu
.etaxonomy
.cdm
.api
.service
.search
.QueryFactory
;
51 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResult
;
52 import eu
.etaxonomy
.cdm
.api
.service
.search
.SearchResultBuilder
;
53 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
54 import eu
.etaxonomy
.cdm
.database
.PermissionDeniedException
;
55 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
56 import eu
.etaxonomy
.cdm
.model
.CdmBaseType
;
57 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
58 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
59 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
60 import eu
.etaxonomy
.cdm
.model
.common
.ReferencedEntityBase
;
61 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
62 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
.Direction
;
63 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
64 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
65 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementSource
;
66 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
67 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationship
;
68 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationshipType
;
69 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
70 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
71 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
72 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
73 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
74 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
75 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
76 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignationStatus
;
77 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
78 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
79 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
80 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
81 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
82 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IReferencedEntityDao
;
83 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ITermVocabularyDao
;
84 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.IHomotypicalGroupDao
;
85 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.INomenclaturalStatusDao
;
86 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
87 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITypeDesignationDao
;
88 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
89 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
90 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedText
;
91 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
92 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
96 @Transactional(readOnly
= true)
97 public class NameServiceImpl
extends IdentifiableServiceBase
<TaxonNameBase
,ITaxonNameDao
> implements INameService
{
98 static private final Logger logger
= Logger
.getLogger(NameServiceImpl
.class);
101 protected ITermVocabularyDao vocabularyDao
;
103 protected IOrderedTermVocabularyDao orderedVocabularyDao
;
105 @Qualifier("refEntDao")
106 protected IReferencedEntityDao
<ReferencedEntityBase
> referencedEntityDao
;
108 private INomenclaturalStatusDao nomStatusDao
;
110 private ITypeDesignationDao typeDesignationDao
;
112 private IHomotypicalGroupDao homotypicalGroupDao
;
114 private ICdmGenericDao genericDao
;
116 private ILuceneIndexToolProvider luceneIndexToolProvider
;
121 public NameServiceImpl(){
122 if (logger
.isDebugEnabled()) { logger
.debug("Load NameService Bean"); }
125 //********************* METHODS ****************************************************************//
128 * @see eu.etaxonomy.cdm.api.service.ServiceBase#delete(eu.etaxonomy.cdm.model.common.CdmBase)
131 public DeleteResult
delete(TaxonNameBase name
){
132 NameDeletionConfigurator config
= new NameDeletionConfigurator();
133 DeleteResult result
= delete(name
, config
);
141 * @see eu.etaxonomy.cdm.api.service.INameService#delete(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.api.service.NameDeletionConfigurator)
144 public DeleteResult
delete(TaxonNameBase name
, NameDeletionConfigurator config
) {
145 DeleteResult result
= new DeleteResult();
151 List
<String
> messages
= new ArrayList
<String
>();
153 messages
= this.isDeletable(name
, config
);
155 result
.addException(e
);
159 if (messages
.isEmpty()){
160 //remove references to this name
161 // if (config.isRemoveAllNameRelationships()){
162 removeNameRelationshipsByDeleteConfig(name
, config
);
164 //remove name from homotypical group
165 HomotypicalGroup homotypicalGroup
= name
.getHomotypicalGroup();
166 if (homotypicalGroup
!= null){
167 homotypicalGroup
.removeTypifiedName(name
);
175 /*check if this name is still used somewhere
178 if (! name.getNameRelations().isEmpty() && !config.isRemoveAllNameRelationships()){
179 String message = "Name can't be deleted as it is used in name relationship(s). Remove name relationships prior to deletion.";
180 throw new ReferencedObjectUndeletableException(message);
185 if (! name.getTaxonBases().isEmpty()){
186 String message = "Name can't be deleted as it is used in concept(s). Remove or change concept prior to deletion.";
187 throw new ReferencedObjectUndeletableException(message);
190 //hybrid relationships
191 if (name.isInstanceOf(NonViralName.class)){
192 NonViralName nvn = CdmBase.deproxy(name, NonViralName.class);
193 // if (! nvn.getHybridChildRelations().isEmpty()){
194 // String message = "Name can't be deleted as it is a child in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
195 // throw new RuntimeException(message);
197 if (! nvn.getHybridParentRelations().isEmpty()){
198 String message = "Name can't be deleted as it is a parent in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
199 throw new ReferencedObjectUndeletableException(message);
203 //all type designation relationships are removed as they belong to the name
204 deleteTypeDesignation(name
, null);
205 // //type designations
206 // if (! name.getTypeDesignations().isEmpty()){
207 // String message = "Name can't be deleted as it has types. Remove types prior to deletion.";
208 // throw new ReferrencedObjectUndeletableException(message);
211 /*check references with only reverse mapping
212 Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(name);
213 for (CdmBase referencingObject : referencingObjects){
214 //DerivedUnit?.storedUnder
215 if (referencingObject.isInstanceOf(DerivedUnit.class)){
216 String message = "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";
217 message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnit.class).getTitleCache());
218 throw new ReferencedObjectUndeletableException(message);
220 //DescriptionElementSource#nameUsedInSource
221 if (referencingObject.isInstanceOf(DescriptionElementSource.class)){
222 String message = "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";
223 throw new ReferencedObjectUndeletableException(message);
225 //NameTypeDesignation#typeName
226 if (referencingObject.isInstanceOf(NameTypeDesignation.class)){
227 String message = "Name can't be deleted as it is used as a name type in a NameTypeDesignation";
228 throw new ReferencedObjectUndeletableException(message);
231 //TaxonNameDescriptions#taxonName
232 //deleted via cascade?
234 //NomenclaturalStatus
235 //deleted via cascade?
239 //TODO inline references
241 if (!config.isIgnoreIsBasionymFor() && name.isGroupsBasionym()){
242 String message = "Name can't be deleted as it is a basionym.";
243 throw new ReferencedObjectUndeletableException(message);
245 if (!config.isIgnoreHasBasionym() && (name.getBasionyms().size()>0)){
246 String message = "Name can't be deleted as it has a basionym.";
247 throw new ReferencedObjectUndeletableException(message);
249 if (!config.isIgnoreIsReplacedSynonymFor() && name.isReplacedSynonym()){
250 String message = "Name can't be deleted as it is a replaced synonym.";
251 throw new ReferencedObjectUndeletableException(message);
253 if (!config.isIgnoreHasReplacedSynonym() && (name.getReplacedSynonyms().size()>0)){
254 String message = "Name can't be deleted as it has a replaced synonym.";
255 throw new ReferencedObjectUndeletableException(message);
260 UUID nameUuid
= dao
.delete(name
);
262 result
.addException(e
);
268 for (String message
: messages
){
269 result
.addException(new ReferencedObjectUndeletableException(message
));
276 * @see eu.etaxonomy.cdm.api.service.INameService#deleteTypeDesignation(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.model.name.TypeDesignationBase)
279 public void deleteTypeDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
){
280 if (name
== null && typeDesignation
== null){
282 }else if (name
!= null && typeDesignation
!= null){
283 removeSingleDesignation(name
, typeDesignation
);
284 }else if (name
!= null){
285 Set
<TypeDesignationBase
> designationSet
= new HashSet
<TypeDesignationBase
>(name
.getTypeDesignations());
286 for (Object o
: designationSet
){
287 TypeDesignationBase desig
= CdmBase
.deproxy(o
, TypeDesignationBase
.class);
288 removeSingleDesignation(name
, desig
);
290 }else if (typeDesignation
!= null){
291 Set
<TaxonNameBase
> nameSet
= new HashSet
<TaxonNameBase
>(typeDesignation
.getTypifiedNames());
292 for (Object o
: nameSet
){
293 TaxonNameBase singleName
= CdmBase
.deproxy(o
, TaxonNameBase
.class);
294 removeSingleDesignation(singleName
, typeDesignation
);
301 * @param typeDesignation
303 private void removeSingleDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
) {
304 name
.removeTypeDesignation(typeDesignation
);
305 if (typeDesignation
.getTypifiedNames().isEmpty()){
306 typeDesignation
.removeType();
307 typeDesignationDao
.delete(typeDesignation
);
317 private void removeNameRelationshipsByDeleteConfig(TaxonNameBase
<?
,?
> name
, NameDeletionConfigurator config
) {
319 if (config
.isRemoveAllNameRelationships()){
320 Set
<NameRelationship
> rels
= getModifiableSet(name
.getNameRelations());
321 for (NameRelationship rel
: rels
){
322 name
.removeNameRelationship(rel
);
325 //relations to this name
326 Set
<NameRelationship
> rels
= getModifiableSet(name
.getRelationsToThisName());
327 for (NameRelationship rel
: rels
){
328 if (config
.isIgnoreHasBasionym() && NameRelationshipType
.BASIONYM().equals(rel
.getType() )){
329 name
.removeNameRelationship(rel
);
330 }else if (config
.isIgnoreHasReplacedSynonym() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
331 name
.removeNameRelationship(rel
);
334 //relations from this name
335 rels
= getModifiableSet(name
.getRelationsFromThisName());
336 for (NameRelationship rel
: rels
){
337 if (config
.isIgnoreIsBasionymFor() && NameRelationshipType
.BASIONYM().equals(rel
.getType()) ){
338 name
.removeNameRelationship(rel
);
339 }else if (config
.isIgnoreIsReplacedSynonymFor() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
340 name
.removeNameRelationship(rel
);
345 } catch (Exception e
) {
346 throw new RuntimeException(e
);
354 private Set
<NameRelationship
> getModifiableSet(Set
<NameRelationship
> relations
) {
355 Set
<NameRelationship
> rels
= new HashSet
<NameRelationship
>();
356 for (NameRelationship rel
: relations
){
362 //********************* METHODS ****************************************************************//
365 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
366 * duplicate of findByName
370 public List
getNamesByName(String name
){
371 return super.findCdmObjectsByTitle(name
);
375 * TODO candidate for harmonization
376 * new name findByName
379 public List
<NonViralName
> getNamesByNameCache(String nameCache
){
380 List result
= dao
.findByName(nameCache
, MatchMode
.EXACT
, null, null, null, null);
386 * TODO candidate for harmonization
387 * new name saveHomotypicalGroups
392 public List
<NonViralName
> findNamesByTitleCache(String titleCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
393 List result
= dao
.findByTitle(titleCache
, matchMode
, null, null, null ,propertyPaths
);
398 * TODO candidate for harmonization
399 * new name saveHomotypicalGroups
404 public List
<NonViralName
> findNamesByNameCache(String nameCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
405 List result
= dao
.findByName(nameCache
, matchMode
, null, null, null ,propertyPaths
);
410 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
411 * Replace by load(UUID, propertyPaths)
415 public NonViralName
findNameByUuid(UUID uuid
, List
<String
> propertyPaths
){
416 return (NonViralName
)dao
.findByUuid(uuid
, null ,propertyPaths
);
420 * TODO candidate for harmonization
423 public List
getNamesByName(String name
, CdmBase sessionObject
){
424 return super.findCdmObjectsByTitle(name
, sessionObject
);
428 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
429 * duplicate of findByTitle(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths)
433 public List
findNamesByTitle(String title
){
434 return super.findCdmObjectsByTitle(title
);
438 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
439 * duplicate of findByTitle()
443 public List
findNamesByTitle(String title
, CdmBase sessionObject
){
444 return super.findCdmObjectsByTitle(title
, sessionObject
);
448 * TODO candidate for harmonization
449 * new name saveHomotypicalGroups
452 @Transactional(readOnly
= false)
453 public Map
<UUID
, HomotypicalGroup
> saveAllHomotypicalGroups(Collection
<HomotypicalGroup
> homotypicalGroups
){
454 return homotypicalGroupDao
.saveAll(homotypicalGroups
);
458 * TODO candidate for harmonization
459 * new name saveTypeDesignations
462 @Transactional(readOnly
= false)
463 public Map
<UUID
, TypeDesignationBase
> saveTypeDesignationAll(Collection
<TypeDesignationBase
> typeDesignationCollection
){
464 return typeDesignationDao
.saveAll(typeDesignationCollection
);
468 * TODO candidate for harmonization
469 * new name saveReferencedEntities
472 @Transactional(readOnly
= false)
473 public Map
<UUID
, ReferencedEntityBase
> saveReferencedEntitiesAll(Collection
<ReferencedEntityBase
> referencedEntityCollection
){
474 return referencedEntityDao
.saveAll(referencedEntityCollection
);
478 * TODO candidate for harmonization
481 public List
<TaxonNameBase
> getAllNames(int limit
, int start
){
482 return dao
.list(limit
, start
);
486 * TODO candidate for harmonization
487 * new name getNomenclaturalStatus
490 public List
<NomenclaturalStatus
> getAllNomenclaturalStatus(int limit
, int start
){
491 return nomStatusDao
.list(limit
, start
);
495 * TODO candidate for harmonization
496 * new name getTypeDesignations
499 public List
<TypeDesignationBase
> getAllTypeDesignations(int limit
, int start
){
500 return typeDesignationDao
.getAllTypeDesignations(limit
, start
);
503 * FIXME Candidate for harmonization
504 * homotypicalGroupService.list
507 public List
<HomotypicalGroup
> getAllHomotypicalGroups(int limit
, int start
){
508 return homotypicalGroupDao
.list(limit
, start
);
512 * FIXME Candidate for harmonization
517 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
518 return dao
.getAllRelationships(limit
, start
);
522 * FIXME Candidate for harmonization
523 * is this not the same as termService.getVocabulary(VocabularyEnum.Rank)
524 * since this returns OrderedTermVocabulary
527 * @see eu.etaxonomy.cdm.api.service.INameService#getRankVocabulary()
530 public OrderedTermVocabulary
<Rank
> getRankVocabulary() {
531 String uuidString
= "ef0d1ce1-26e3-4e83-b47b-ca74eed40b1b";
532 UUID uuid
= UUID
.fromString(uuidString
);
533 OrderedTermVocabulary
<Rank
> rankVocabulary
=
534 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
535 return rankVocabulary
;
539 * FIXME Candidate for harmonization
540 * is this the same as termService.getVocabulary(VocabularyEnum.NameRelationshipType)
542 * @see eu.etaxonomy.cdm.api.service.INameService#getNameRelationshipTypeVocabulary()
545 public TermVocabulary
<NameRelationshipType
> getNameRelationshipTypeVocabulary() {
546 String uuidString
= "6878cb82-c1a4-4613-b012-7e73b413c8cd";
547 UUID uuid
= UUID
.fromString(uuidString
);
548 TermVocabulary
<NameRelationshipType
> nameRelTypeVocabulary
=
549 vocabularyDao
.findByUuid(uuid
);
550 return nameRelTypeVocabulary
;
554 * FIXME Candidate for harmonization
555 * is this the same as termService.getVocabulary(VocabularyEnum.StatusType)
557 * @see eu.etaxonomy.cdm.api.service.INameService#getStatusTypeVocabulary()
560 public TermVocabulary
<NomenclaturalStatusType
> getStatusTypeVocabulary() {
561 String uuidString
= "bb28cdca-2f8a-4f11-9c21-517e9ae87f1f";
562 UUID uuid
= UUID
.fromString(uuidString
);
563 TermVocabulary
<NomenclaturalStatusType
> nomStatusTypeVocabulary
=
564 vocabularyDao
.findByUuid(uuid
);
565 return nomStatusTypeVocabulary
;
569 * FIXME Candidate for harmonization
570 * is this the same as termService.getVocabulary(VocabularyEnum.SpecimenTypeDesignationStatus)
572 * @see eu.etaxonomy.cdm.api.service.INameService#getTypeDesignationStatusVocabulary()
575 public TermVocabulary
<SpecimenTypeDesignationStatus
> getSpecimenTypeDesignationStatusVocabulary() {
576 String uuidString
= "ab177bd7-d3c8-4e58-a388-226fff6ba3c2";
577 UUID uuid
= UUID
.fromString(uuidString
);
578 TermVocabulary
<SpecimenTypeDesignationStatus
> typeDesigStatusVocabulary
=
579 vocabularyDao
.findByUuid(uuid
);
580 return typeDesigStatusVocabulary
;
584 * FIXME Candidate for harmonization
585 * is this the same as termService.getVocabulary(VocabularyEnum.SpecimenTypeDesignationStatus)
586 * and also seems to duplicate the above method, differing only in the DAO used and the return type
588 * @see eu.etaxonomy.cdm.api.service.INameService#getTypeDesignationStatusVocabulary()
591 public OrderedTermVocabulary
<SpecimenTypeDesignationStatus
> getSpecimenTypeDesignationVocabulary() {
592 String uuidString
= "ab177bd7-d3c8-4e58-a388-226fff6ba3c2";
593 UUID uuid
= UUID
.fromString(uuidString
);
594 OrderedTermVocabulary
<SpecimenTypeDesignationStatus
> typeDesignationVocabulary
=
595 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
596 return typeDesignationVocabulary
;
602 protected void setDao(ITaxonNameDao dao
) {
607 public Pager
<HybridRelationship
> getHybridNames(NonViralName name
, HybridRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
608 Integer numberOfResults
= dao
.countHybridNames(name
, type
);
610 List
<HybridRelationship
> results
= new ArrayList
<HybridRelationship
>();
611 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
612 results
= dao
.getHybridNames(name
, type
, pageSize
, pageNumber
,orderHints
,propertyPaths
);
615 return new DefaultPagerImpl
<HybridRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
619 * @see eu.etaxonomy.cdm.api.service.INameService#listNameRelationships(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.model.common.RelationshipBase.Direction, eu.etaxonomy.cdm.model.name.NameRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
622 public List
<NameRelationship
> listNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
623 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
625 Integer numberOfResults
= dao
.countNameRelationships(name
, direction
, type
);
627 List
<NameRelationship
> results
= new ArrayList
<NameRelationship
>();
628 if (AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
629 results
= dao
.getNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
635 protected LuceneSearch
prepareFindByFuzzyNameSearch(Class
<?
extends CdmBase
> clazz
,
639 List
<Language
> languages
,
640 boolean highlightFragments
) {
641 String similarity
= Float
.toString(accuracy
);
642 String searchSuffix
= "~" + similarity
;
645 BooleanQuery finalQuery
= new BooleanQuery(false);
646 BooleanQuery textQuery
= new BooleanQuery(false);
648 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
649 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
651 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
652 // luceneSearch.setSortFields(sortFields);
654 // ---- search criteria
655 luceneSearch
.setCdmTypRestriction(clazz
);
657 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
658 if(nvn
.getGenusOrUninomial() != null && !nvn
.getGenusOrUninomial().equals("")) {
659 fltq
.addTerms(nvn
.getGenusOrUninomial().toLowerCase(), "genusOrUninomial", accuracy
, 3);
661 //textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);
662 textQuery
.add(queryFactory
.newTermQuery("genusOrUninomial", "_null_", false), Occur
.MUST
);
665 if(nvn
.getInfraGenericEpithet() != null && !nvn
.getInfraGenericEpithet().equals("")){
666 fltq
.addTerms(nvn
.getInfraGenericEpithet().toLowerCase(), "infraGenericEpithet", accuracy
, 3);
668 //textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
669 textQuery
.add(queryFactory
.newTermQuery("infraGenericEpithet", "_null_", false), Occur
.MUST
);
672 if(nvn
.getSpecificEpithet() != null && !nvn
.getSpecificEpithet().equals("")){
673 fltq
.addTerms(nvn
.getSpecificEpithet().toLowerCase(), "specificEpithet", accuracy
, 3);
675 //textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
676 textQuery
.add(queryFactory
.newTermQuery("specificEpithet", "_null_", false), Occur
.MUST
);
679 if(nvn
.getInfraSpecificEpithet() != null && !nvn
.getInfraSpecificEpithet().equals("")){
680 fltq
.addTerms(nvn
.getInfraSpecificEpithet().toLowerCase(), "infraSpecificEpithet", accuracy
, 3);
682 //textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
683 textQuery
.add(queryFactory
.newTermQuery("infraSpecificEpithet", "_null_", false), Occur
.MUST
);
686 if(nvn
.getAuthorshipCache() != null && !nvn
.getAuthorshipCache().equals("")){
687 fltq
.addTerms(nvn
.getAuthorshipCache().toLowerCase(), "authorshipCache", accuracy
, 3);
689 //textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);
692 textQuery
.add(fltq
, Occur
.MUST
);
694 finalQuery
.add(textQuery
, Occur
.MUST
);
696 luceneSearch
.setQuery(finalQuery
);
698 if(highlightFragments
){
699 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
704 protected LuceneSearch
prepareFindByFuzzyNameCacheSearch(Class
<?
extends CdmBase
> clazz
,
708 List
<Language
> languages
,
709 boolean highlightFragments
) {
711 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
712 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
714 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
715 // luceneSearch.setSortFields(sortFields);
717 // ---- search criteria
718 luceneSearch
.setCdmTypRestriction(clazz
);
719 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
721 fltq
.addTerms(name
, "nameCache", accuracy
, 3);
723 BooleanQuery finalQuery
= new BooleanQuery(false);
725 finalQuery
.add(fltq
, Occur
.MUST
);
727 luceneSearch
.setQuery(finalQuery
);
729 if(highlightFragments
){
730 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
735 protected LuceneSearch
prepareFindByExactNameSearch(Class
<?
extends CdmBase
> clazz
,
738 List
<Language
> languages
,
739 boolean highlightFragments
) {
740 BooleanQuery finalQuery
= new BooleanQuery();
741 BooleanQuery textQuery
= new BooleanQuery();
743 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
744 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
746 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
747 // luceneSearch.setSortFields(sortFields);
749 // ---- search criteria
750 luceneSearch
.setCdmTypRestriction(clazz
);
752 if(name
!= null && !name
.equals("")) {
754 textQuery
.add(new WildcardQuery(new Term("nameCache", name
+ "*")), Occur
.MUST
);
756 textQuery
.add(queryFactory
.newTermQuery("nameCache", name
, false), Occur
.MUST
);
760 luceneSearch
.setQuery(textQuery
);
762 if(highlightFragments
){
763 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
769 public List
<SearchResult
<TaxonNameBase
>> findByNameFuzzySearch(
772 List
<Language
> languages
,
773 boolean highlightFragments
,
774 List
<String
> propertyPaths
,
775 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
777 logger
.info("Name to fuzzy search for : " + name
);
778 // parse the input name
779 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
780 NonViralName nvn
= parser
.parseFullName(name
);
781 if(name
!= null && !name
.equals("") && nvn
== null) {
782 throw new ParseException("Could not parse name " + name
);
784 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
786 // --- execute search
787 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
790 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
791 idFieldMap
.put(CdmBaseType
.NONVIRALNAME
, "id");
793 // --- initialize taxa, highlight matches ....
794 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
796 @SuppressWarnings("rawtypes")
797 List
<SearchResult
<TaxonNameBase
>> searchResults
= searchResultBuilder
.createResultSet(
798 topDocs
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
800 return searchResults
;
805 public List
<DocumentSearchResult
> findByNameFuzzySearch(
808 List
<Language
> languages
,
809 boolean highlightFragments
,
810 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
812 logger
.info("Name to fuzzy search for : " + name
);
813 // parse the input name
814 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
815 NonViralName nvn
= parser
.parseFullName(name
);
816 if(name
!= null && !name
.equals("") && nvn
== null) {
817 throw new ParseException("Could not parse name " + name
);
819 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
821 // --- execute search
822 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
824 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
826 // --- initialize taxa, highlight matches ....
827 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
829 @SuppressWarnings("rawtypes")
830 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
832 return searchResults
;
836 public List
<DocumentSearchResult
> findByFuzzyNameCacheSearch(
839 List
<Language
> languages
,
840 boolean highlightFragments
,
841 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
843 logger
.info("Name to fuzzy search for : " + name
);
845 LuceneSearch luceneSearch
= prepareFindByFuzzyNameCacheSearch(null, name
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
847 // --- execute search
848 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
849 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
851 // --- initialize taxa, highlight matches ....
852 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
854 @SuppressWarnings("rawtypes")
855 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
857 return searchResults
;
861 public List
<DocumentSearchResult
> findByNameExactSearch(
864 List
<Language
> languages
,
865 boolean highlightFragments
,
866 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
868 logger
.info("Name to exact search for : " + name
);
870 LuceneSearch luceneSearch
= prepareFindByExactNameSearch(null, name
, wildcard
, languages
, highlightFragments
);
872 // --- execute search
875 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
877 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
879 // --- initialize taxa, highlight matches ....
880 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
882 @SuppressWarnings("rawtypes")
883 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
885 return searchResults
;
889 * @see eu.etaxonomy.cdm.api.service.INameService#pageNameRelationships(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.model.common.RelationshipBase.Direction, eu.etaxonomy.cdm.model.name.NameRelationshipType, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
892 public Pager
<NameRelationship
> pageNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
893 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
894 List
<NameRelationship
> results
= listNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
895 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
899 public List
<NameRelationship
> listFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
900 return listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
904 public Pager
<NameRelationship
> pageFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
905 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
906 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
910 public List
<NameRelationship
> listToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
911 return listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
915 public Pager
<NameRelationship
> pageToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
916 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
917 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
921 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
922 Integer pageSize
, Integer pageNumber
) {
923 return getTypeDesignations(name
, status
, pageSize
, pageNumber
, null);
927 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
928 Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
){
929 Integer numberOfResults
= dao
.countTypeDesignations(name
, status
);
931 List
<TypeDesignationBase
> results
= new ArrayList
<TypeDesignationBase
>();
932 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) {
933 results
= dao
.getTypeDesignations(name
, null, status
, pageSize
, pageNumber
, propertyPaths
);
936 return new DefaultPagerImpl
<TypeDesignationBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
940 * FIXME Candidate for harmonization
944 public Pager
<TaxonNameBase
> searchNames(String uninomial
,String infraGenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
945 List
<String
> propertyPaths
) {
946 Integer numberOfResults
= dao
.countNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
948 List
<TaxonNameBase
> results
= new ArrayList
<TaxonNameBase
>();
949 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
950 results
= dao
.searchNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
953 return new DefaultPagerImpl
<TaxonNameBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
957 * @see eu.etaxonomy.cdm.api.service.INameService#getUuidAndTitleCacheOfNames()
960 public List
<UuidAndTitleCache
> getUuidAndTitleCacheOfNames() {
961 return dao
.getUuidAndTitleCacheOfNames();
965 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
) {
966 Integer numberOfResults
= dao
.countByName(clazz
, queryString
, matchmode
, criteria
);
968 List
<TaxonNameBase
> results
= new ArrayList
<TaxonNameBase
>();
969 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
970 results
= dao
.findByName(clazz
, queryString
, matchmode
, criteria
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
973 return new DefaultPagerImpl
<TaxonNameBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
977 public HomotypicalGroup
findHomotypicalGroup(UUID uuid
) {
978 return homotypicalGroupDao
.findByUuid(uuid
);
983 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
986 @Transactional(readOnly
= false)
987 public void updateTitleCache(Class
<?
extends TaxonNameBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonNameBase
> cacheStrategy
, IProgressMonitor monitor
) {
989 clazz
= TaxonNameBase
.class;
991 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
996 protected void setOtherCachesNull(TaxonNameBase name
) {
997 if (name
.isInstanceOf(NonViralName
.class)){
998 NonViralName
<?
> nvn
= CdmBase
.deproxy(name
, NonViralName
.class);
999 if (! nvn
.isProtectedNameCache()){
1000 nvn
.setNameCache(null, false);
1002 if (! nvn
.isProtectedAuthorshipCache()){
1003 nvn
.setAuthorshipCache(null, false);
1005 if (! nvn
.isProtectedFullTitleCache()){
1006 nvn
.setFullTitleCache(null, false);
1012 * @see eu.etaxonomy.cdm.api.service.INameService#getTaggedName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1015 public List
<TaggedText
> getTaggedName(UUID uuid
) {
1016 TaxonNameBase taxonNameBase
= dao
.load(uuid
);
1017 List taggedName
= taxonNameBase
.getTaggedName();
1022 public List
<String
> isDeletable(TaxonNameBase name
, DeleteConfiguratorBase config
){
1023 List
<String
> result
= new ArrayList
<String
>();
1024 name
= (TaxonNameBase
)HibernateProxyHelper
.deproxy(name
);
1025 NameDeletionConfigurator nameConfig
= null;
1026 if (config
instanceof NameDeletionConfigurator
){
1027 nameConfig
= (NameDeletionConfigurator
) config
;
1029 result
.add("The delete configurator should be of the type NameDeletionConfigurator.");
1033 if (!name
.getNameRelations().isEmpty() && !nameConfig
.isRemoveAllNameRelationships()){
1034 if (!nameConfig
.isIgnoreIsBasionymFor() && name
.isGroupsBasionym()){
1035 String message
= "Name can't be deleted as it is a basionym.";
1036 result
.add(message
);
1038 if (!nameConfig
.isIgnoreHasBasionym() && (name
.getBasionyms().size()>0)){
1039 String message
= "Name can't be deleted as it has a basionym.";
1040 result
.add(message
);
1042 Set
<NameRelationship
> relationships
= name
.getNameRelations();
1043 for (NameRelationship rel
: relationships
){
1044 if (!rel
.getType().equals(NameRelationshipType
.BASIONYM())){
1045 String message
= "Name can't be deleted as it is used in name relationship(s). Remove name relationships prior to deletion.";
1046 result
.add(message
);
1055 if (! name
.getTaxonBases().isEmpty()){
1056 String message
= "Name can't be deleted as it is used in concept(s). Remove or change concept prior to deletion.";
1057 result
.add(message
);
1060 //hybrid relationships
1061 if (name
.isInstanceOf(NonViralName
.class)){
1062 NonViralName nvn
= CdmBase
.deproxy(name
, NonViralName
.class);
1063 if (! nvn
.getHybridParentRelations().isEmpty()){
1064 String message
= "Name can't be deleted as it is a parent in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
1065 result
.add(message
);
1068 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(name
);
1069 for (CdmBase referencingObject
: referencingObjects
){
1070 //DerivedUnit?.storedUnder
1071 if (referencingObject
.isInstanceOf(DerivedUnit
.class)){
1072 String message
= "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";
1073 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnit
.class).getTitleCache());
1074 result
.add(message
);
1076 //DescriptionElementSource#nameUsedInSource
1077 if (referencingObject
.isInstanceOf(DescriptionElementSource
.class)){
1078 String message
= "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";
1079 result
.add(message
);
1081 //NameTypeDesignation#typeName
1082 if (referencingObject
.isInstanceOf(NameTypeDesignation
.class)){
1083 String message
= "Name can't be deleted as it is used as a name type in a NameTypeDesignation";
1084 result
.add(message
);
1091 //TODO inline references
1094 if (!nameConfig
.isIgnoreIsReplacedSynonymFor() && name
.isReplacedSynonym()){
1095 String message
= "Name can't be deleted as it is a replaced synonym.";
1096 result
.add(message
);
1098 if (!nameConfig
.isIgnoreHasReplacedSynonym() && (name
.getReplacedSynonyms().size()>0)){
1099 String message
= "Name can't be deleted as it has a replaced synonym.";
1100 result
.add(message
);