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
.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
.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
.OrderedTermVocabulary
;
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
.common
.TermVocabulary
;
61 import eu
.etaxonomy
.cdm
.model
.common
.UuidAndTitleCache
;
62 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementSource
;
63 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
64 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationship
;
65 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationshipType
;
66 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
67 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
68 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
69 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
70 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
71 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
72 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
73 import eu
.etaxonomy
.cdm
.model
.name
.SpecimenTypeDesignationStatus
;
74 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
75 import eu
.etaxonomy
.cdm
.model
.name
.TypeDesignationBase
;
76 import eu
.etaxonomy
.cdm
.model
.occurrence
.DerivedUnit
;
77 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ICdmGenericDao
;
78 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IOrderedTermVocabularyDao
;
79 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.IReferencedEntityDao
;
80 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ITermVocabularyDao
;
81 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.IHomotypicalGroupDao
;
82 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.INomenclaturalStatusDao
;
83 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITaxonNameDao
;
84 import eu
.etaxonomy
.cdm
.persistence
.dao
.name
.ITypeDesignationDao
;
85 import eu
.etaxonomy
.cdm
.persistence
.query
.MatchMode
;
86 import eu
.etaxonomy
.cdm
.persistence
.query
.OrderHint
;
87 import eu
.etaxonomy
.cdm
.strategy
.cache
.TaggedText
;
88 import eu
.etaxonomy
.cdm
.strategy
.cache
.common
.IIdentifiableEntityCacheStrategy
;
89 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
93 @Transactional(readOnly
= true)
94 public class NameServiceImpl
extends IdentifiableServiceBase
<TaxonNameBase
,ITaxonNameDao
> implements INameService
{
95 static private final Logger logger
= Logger
.getLogger(NameServiceImpl
.class);
98 protected ITermVocabularyDao vocabularyDao
;
100 protected IOrderedTermVocabularyDao orderedVocabularyDao
;
102 @Qualifier("refEntDao")
103 protected IReferencedEntityDao
<ReferencedEntityBase
> referencedEntityDao
;
105 private INomenclaturalStatusDao nomStatusDao
;
107 private ITypeDesignationDao typeDesignationDao
;
109 private IHomotypicalGroupDao homotypicalGroupDao
;
111 private ICdmGenericDao genericDao
;
113 private ILuceneIndexToolProvider luceneIndexToolProvider
;
118 public NameServiceImpl(){
119 if (logger
.isDebugEnabled()) { logger
.debug("Load NameService Bean"); }
122 //********************* METHODS ****************************************************************//
125 * @see eu.etaxonomy.cdm.api.service.ServiceBase#delete(eu.etaxonomy.cdm.model.common.CdmBase)
128 public String
delete(TaxonNameBase name
){
129 NameDeletionConfigurator config
= new NameDeletionConfigurator();
130 String result
= delete(name
, config
);
138 * @see eu.etaxonomy.cdm.api.service.INameService#delete(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.api.service.NameDeletionConfigurator)
141 public String
delete(TaxonNameBase name
, NameDeletionConfigurator config
) {
146 List
<String
> messages
= this.isDeletable(name
, config
);
148 if (messages
.isEmpty()){
149 //remove references to this name
150 // if (config.isRemoveAllNameRelationships()){
151 removeNameRelationshipsByDeleteConfig(name
, config
);
153 //remove name from homotypical group
154 HomotypicalGroup homotypicalGroup
= name
.getHomotypicalGroup();
155 if (homotypicalGroup
!= null){
156 homotypicalGroup
.removeTypifiedName(name
);
164 /*check if this name is still used somewhere
167 if (! name.getNameRelations().isEmpty() && !config.isRemoveAllNameRelationships()){
168 String message = "Name can't be deleted as it is used in name relationship(s). Remove name relationships prior to deletion.";
169 throw new ReferencedObjectUndeletableException(message);
174 if (! name.getTaxonBases().isEmpty()){
175 String message = "Name can't be deleted as it is used in concept(s). Remove or change concept prior to deletion.";
176 throw new ReferencedObjectUndeletableException(message);
179 //hybrid relationships
180 if (name.isInstanceOf(NonViralName.class)){
181 NonViralName nvn = CdmBase.deproxy(name, NonViralName.class);
182 // if (! nvn.getHybridChildRelations().isEmpty()){
183 // String message = "Name can't be deleted as it is a child in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
184 // throw new RuntimeException(message);
186 if (! nvn.getHybridParentRelations().isEmpty()){
187 String message = "Name can't be deleted as it is a parent in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
188 throw new ReferencedObjectUndeletableException(message);
192 //all type designation relationships are removed as they belong to the name
193 deleteTypeDesignation(name
, null);
194 // //type designations
195 // if (! name.getTypeDesignations().isEmpty()){
196 // String message = "Name can't be deleted as it has types. Remove types prior to deletion.";
197 // throw new ReferrencedObjectUndeletableException(message);
200 /*check references with only reverse mapping
201 Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(name);
202 for (CdmBase referencingObject : referencingObjects){
203 //DerivedUnit?.storedUnder
204 if (referencingObject.isInstanceOf(DerivedUnit.class)){
205 String message = "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";
206 message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnit.class).getTitleCache());
207 throw new ReferencedObjectUndeletableException(message);
209 //DescriptionElementSource#nameUsedInSource
210 if (referencingObject.isInstanceOf(DescriptionElementSource.class)){
211 String message = "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";
212 throw new ReferencedObjectUndeletableException(message);
214 //NameTypeDesignation#typeName
215 if (referencingObject.isInstanceOf(NameTypeDesignation.class)){
216 String message = "Name can't be deleted as it is used as a name type in a NameTypeDesignation";
217 throw new ReferencedObjectUndeletableException(message);
220 //TaxonNameDescriptions#taxonName
221 //deleted via cascade?
223 //NomenclaturalStatus
224 //deleted via cascade?
228 //TODO inline references
230 if (!config.isIgnoreIsBasionymFor() && name.isGroupsBasionym()){
231 String message = "Name can't be deleted as it is a basionym.";
232 throw new ReferencedObjectUndeletableException(message);
234 if (!config.isIgnoreHasBasionym() && (name.getBasionyms().size()>0)){
235 String message = "Name can't be deleted as it has a basionym.";
236 throw new ReferencedObjectUndeletableException(message);
238 if (!config.isIgnoreIsReplacedSynonymFor() && name.isReplacedSynonym()){
239 String message = "Name can't be deleted as it is a replaced synonym.";
240 throw new ReferencedObjectUndeletableException(message);
242 if (!config.isIgnoreHasReplacedSynonym() && (name.getReplacedSynonyms().size()>0)){
243 String message = "Name can't be deleted as it has a replaced synonym.";
244 throw new ReferencedObjectUndeletableException(message);
249 UUID nameUuid
= dao
.delete(name
);
250 return name
.getUuid().toString();
252 StringBuffer result
= new StringBuffer();
253 for (String message
: messages
){
254 result
.append(message
);
257 return result
.toString();
261 * @see eu.etaxonomy.cdm.api.service.INameService#deleteTypeDesignation(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.model.name.TypeDesignationBase)
264 public void deleteTypeDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
){
265 if (name
== null && typeDesignation
== null){
267 }else if (name
!= null && typeDesignation
!= null){
268 removeSingleDesignation(name
, typeDesignation
);
269 }else if (name
!= null){
270 Set
<TypeDesignationBase
> designationSet
= new HashSet
<TypeDesignationBase
>(name
.getTypeDesignations());
271 for (Object o
: designationSet
){
272 TypeDesignationBase desig
= CdmBase
.deproxy(o
, TypeDesignationBase
.class);
273 removeSingleDesignation(name
, desig
);
275 }else if (typeDesignation
!= null){
276 Set
<TaxonNameBase
> nameSet
= new HashSet
<TaxonNameBase
>(typeDesignation
.getTypifiedNames());
277 for (Object o
: nameSet
){
278 TaxonNameBase singleName
= CdmBase
.deproxy(o
, TaxonNameBase
.class);
279 removeSingleDesignation(singleName
, typeDesignation
);
286 * @param typeDesignation
288 private void removeSingleDesignation(TaxonNameBase name
, TypeDesignationBase typeDesignation
) {
289 name
.removeTypeDesignation(typeDesignation
);
290 if (typeDesignation
.getTypifiedNames().isEmpty()){
291 typeDesignation
.removeType();
292 typeDesignationDao
.delete(typeDesignation
);
302 private void removeNameRelationshipsByDeleteConfig(TaxonNameBase
<?
,?
> name
, NameDeletionConfigurator config
) {
304 if (config
.isRemoveAllNameRelationships()){
305 Set
<NameRelationship
> rels
= getModifiableSet(name
.getNameRelations());
306 for (NameRelationship rel
: rels
){
307 name
.removeNameRelationship(rel
);
310 //relations to this name
311 Set
<NameRelationship
> rels
= getModifiableSet(name
.getRelationsToThisName());
312 for (NameRelationship rel
: rels
){
313 if (config
.isIgnoreHasBasionym() && NameRelationshipType
.BASIONYM().equals(rel
.getType() )){
314 name
.removeNameRelationship(rel
);
315 }else if (config
.isIgnoreHasReplacedSynonym() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
316 name
.removeNameRelationship(rel
);
319 //relations from this name
320 rels
= getModifiableSet(name
.getRelationsFromThisName());
321 for (NameRelationship rel
: rels
){
322 if (config
.isIgnoreIsBasionymFor() && NameRelationshipType
.BASIONYM().equals(rel
.getType()) ){
323 name
.removeNameRelationship(rel
);
324 }else if (config
.isIgnoreIsReplacedSynonymFor() && NameRelationshipType
.REPLACED_SYNONYM().equals(rel
.getType())){
325 name
.removeNameRelationship(rel
);
330 } catch (Exception e
) {
331 throw new RuntimeException(e
);
339 private Set
<NameRelationship
> getModifiableSet(Set
<NameRelationship
> relations
) {
340 Set
<NameRelationship
> rels
= new HashSet
<NameRelationship
>();
341 for (NameRelationship rel
: relations
){
347 //********************* METHODS ****************************************************************//
350 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
351 * duplicate of findByName
355 public List
getNamesByName(String name
){
356 return super.findCdmObjectsByTitle(name
);
360 * TODO candidate for harmonization
361 * new name findByName
364 public List
<NonViralName
> getNamesByNameCache(String nameCache
){
365 List result
= dao
.findByName(nameCache
, MatchMode
.EXACT
, null, null, null, null);
371 * TODO candidate for harmonization
372 * new name saveHomotypicalGroups
377 public List
<NonViralName
> findNamesByTitleCache(String titleCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
378 List result
= dao
.findByTitle(titleCache
, matchMode
, null, null, null ,propertyPaths
);
383 * TODO candidate for harmonization
384 * new name saveHomotypicalGroups
389 public List
<NonViralName
> findNamesByNameCache(String nameCache
, MatchMode matchMode
, List
<String
> propertyPaths
){
390 List result
= dao
.findByName(nameCache
, matchMode
, null, null, null ,propertyPaths
);
395 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
396 * Replace by load(UUID, propertyPaths)
400 public NonViralName
findNameByUuid(UUID uuid
, List
<String
> propertyPaths
){
401 return (NonViralName
)dao
.findByUuid(uuid
, null ,propertyPaths
);
405 * TODO candidate for harmonization
408 public List
getNamesByName(String name
, CdmBase sessionObject
){
409 return super.findCdmObjectsByTitle(name
, sessionObject
);
413 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
414 * duplicate of findByTitle(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths)
418 public List
findNamesByTitle(String title
){
419 return super.findCdmObjectsByTitle(title
);
423 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
424 * duplicate of findByTitle()
428 public List
findNamesByTitle(String title
, CdmBase sessionObject
){
429 return super.findCdmObjectsByTitle(title
, sessionObject
);
433 * TODO candidate for harmonization
434 * new name saveHomotypicalGroups
437 @Transactional(readOnly
= false)
438 public Map
<UUID
, HomotypicalGroup
> saveAllHomotypicalGroups(Collection
<HomotypicalGroup
> homotypicalGroups
){
439 return homotypicalGroupDao
.saveAll(homotypicalGroups
);
443 * TODO candidate for harmonization
444 * new name saveTypeDesignations
447 @Transactional(readOnly
= false)
448 public Map
<UUID
, TypeDesignationBase
> saveTypeDesignationAll(Collection
<TypeDesignationBase
> typeDesignationCollection
){
449 return typeDesignationDao
.saveAll(typeDesignationCollection
);
453 * TODO candidate for harmonization
454 * new name saveReferencedEntities
457 @Transactional(readOnly
= false)
458 public Map
<UUID
, ReferencedEntityBase
> saveReferencedEntitiesAll(Collection
<ReferencedEntityBase
> referencedEntityCollection
){
459 return referencedEntityDao
.saveAll(referencedEntityCollection
);
463 * TODO candidate for harmonization
466 public List
<TaxonNameBase
> getAllNames(int limit
, int start
){
467 return dao
.list(limit
, start
);
471 * TODO candidate for harmonization
472 * new name getNomenclaturalStatus
475 public List
<NomenclaturalStatus
> getAllNomenclaturalStatus(int limit
, int start
){
476 return nomStatusDao
.list(limit
, start
);
480 * TODO candidate for harmonization
481 * new name getTypeDesignations
484 public List
<TypeDesignationBase
> getAllTypeDesignations(int limit
, int start
){
485 return typeDesignationDao
.getAllTypeDesignations(limit
, start
);
488 * FIXME Candidate for harmonization
489 * homotypicalGroupService.list
492 public List
<HomotypicalGroup
> getAllHomotypicalGroups(int limit
, int start
){
493 return homotypicalGroupDao
.list(limit
, start
);
497 * FIXME Candidate for harmonization
502 public List
<RelationshipBase
> getAllRelationships(int limit
, int start
){
503 return dao
.getAllRelationships(limit
, start
);
507 * FIXME Candidate for harmonization
508 * is this not the same as termService.getVocabulary(VocabularyEnum.Rank)
509 * since this returns OrderedTermVocabulary
512 * @see eu.etaxonomy.cdm.api.service.INameService#getRankVocabulary()
515 public OrderedTermVocabulary
<Rank
> getRankVocabulary() {
516 String uuidString
= "ef0d1ce1-26e3-4e83-b47b-ca74eed40b1b";
517 UUID uuid
= UUID
.fromString(uuidString
);
518 OrderedTermVocabulary
<Rank
> rankVocabulary
=
519 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
520 return rankVocabulary
;
524 * FIXME Candidate for harmonization
525 * is this the same as termService.getVocabulary(VocabularyEnum.NameRelationshipType)
527 * @see eu.etaxonomy.cdm.api.service.INameService#getNameRelationshipTypeVocabulary()
530 public TermVocabulary
<NameRelationshipType
> getNameRelationshipTypeVocabulary() {
531 String uuidString
= "6878cb82-c1a4-4613-b012-7e73b413c8cd";
532 UUID uuid
= UUID
.fromString(uuidString
);
533 TermVocabulary
<NameRelationshipType
> nameRelTypeVocabulary
=
534 vocabularyDao
.findByUuid(uuid
);
535 return nameRelTypeVocabulary
;
539 * FIXME Candidate for harmonization
540 * is this the same as termService.getVocabulary(VocabularyEnum.StatusType)
542 * @see eu.etaxonomy.cdm.api.service.INameService#getStatusTypeVocabulary()
545 public TermVocabulary
<NomenclaturalStatusType
> getStatusTypeVocabulary() {
546 String uuidString
= "bb28cdca-2f8a-4f11-9c21-517e9ae87f1f";
547 UUID uuid
= UUID
.fromString(uuidString
);
548 TermVocabulary
<NomenclaturalStatusType
> nomStatusTypeVocabulary
=
549 vocabularyDao
.findByUuid(uuid
);
550 return nomStatusTypeVocabulary
;
554 * FIXME Candidate for harmonization
555 * is this the same as termService.getVocabulary(VocabularyEnum.SpecimenTypeDesignationStatus)
557 * @see eu.etaxonomy.cdm.api.service.INameService#getTypeDesignationStatusVocabulary()
560 public TermVocabulary
<SpecimenTypeDesignationStatus
> getSpecimenTypeDesignationStatusVocabulary() {
561 String uuidString
= "ab177bd7-d3c8-4e58-a388-226fff6ba3c2";
562 UUID uuid
= UUID
.fromString(uuidString
);
563 TermVocabulary
<SpecimenTypeDesignationStatus
> typeDesigStatusVocabulary
=
564 vocabularyDao
.findByUuid(uuid
);
565 return typeDesigStatusVocabulary
;
569 * FIXME Candidate for harmonization
570 * is this the same as termService.getVocabulary(VocabularyEnum.SpecimenTypeDesignationStatus)
571 * and also seems to duplicate the above method, differing only in the DAO used and the return type
573 * @see eu.etaxonomy.cdm.api.service.INameService#getTypeDesignationStatusVocabulary()
576 public OrderedTermVocabulary
<SpecimenTypeDesignationStatus
> getSpecimenTypeDesignationVocabulary() {
577 String uuidString
= "ab177bd7-d3c8-4e58-a388-226fff6ba3c2";
578 UUID uuid
= UUID
.fromString(uuidString
);
579 OrderedTermVocabulary
<SpecimenTypeDesignationStatus
> typeDesignationVocabulary
=
580 (OrderedTermVocabulary
)orderedVocabularyDao
.findByUuid(uuid
);
581 return typeDesignationVocabulary
;
587 protected void setDao(ITaxonNameDao dao
) {
592 public Pager
<HybridRelationship
> getHybridNames(NonViralName name
, HybridRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
593 Integer numberOfResults
= dao
.countHybridNames(name
, type
);
595 List
<HybridRelationship
> results
= new ArrayList
<HybridRelationship
>();
596 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
597 results
= dao
.getHybridNames(name
, type
, pageSize
, pageNumber
,orderHints
,propertyPaths
);
600 return new DefaultPagerImpl
<HybridRelationship
>(pageNumber
, numberOfResults
, pageSize
, results
);
604 * @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)
607 public List
<NameRelationship
> listNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
608 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
610 Integer numberOfResults
= dao
.countNameRelationships(name
, direction
, type
);
612 List
<NameRelationship
> results
= new ArrayList
<NameRelationship
>();
613 if (AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) { // no point checking again
614 results
= dao
.getNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
620 protected LuceneSearch
prepareFindByFuzzyNameSearch(Class
<?
extends CdmBase
> clazz
,
624 List
<Language
> languages
,
625 boolean highlightFragments
) {
626 String similarity
= Float
.toString(accuracy
);
627 String searchSuffix
= "~" + similarity
;
630 BooleanQuery finalQuery
= new BooleanQuery(false);
631 BooleanQuery textQuery
= new BooleanQuery(false);
633 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
634 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
636 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
637 // luceneSearch.setSortFields(sortFields);
639 // ---- search criteria
640 luceneSearch
.setCdmTypRestriction(clazz
);
642 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
643 if(nvn
.getGenusOrUninomial() != null && !nvn
.getGenusOrUninomial().equals("")) {
644 fltq
.addTerms(nvn
.getGenusOrUninomial().toLowerCase(), "genusOrUninomial", accuracy
, 3);
646 //textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);
647 textQuery
.add(queryFactory
.newTermQuery("genusOrUninomial", "_null_", false), Occur
.MUST
);
650 if(nvn
.getInfraGenericEpithet() != null && !nvn
.getInfraGenericEpithet().equals("")){
651 fltq
.addTerms(nvn
.getInfraGenericEpithet().toLowerCase(), "infraGenericEpithet", accuracy
, 3);
653 //textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
654 textQuery
.add(queryFactory
.newTermQuery("infraGenericEpithet", "_null_", false), Occur
.MUST
);
657 if(nvn
.getSpecificEpithet() != null && !nvn
.getSpecificEpithet().equals("")){
658 fltq
.addTerms(nvn
.getSpecificEpithet().toLowerCase(), "specificEpithet", accuracy
, 3);
660 //textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
661 textQuery
.add(queryFactory
.newTermQuery("specificEpithet", "_null_", false), Occur
.MUST
);
664 if(nvn
.getInfraSpecificEpithet() != null && !nvn
.getInfraSpecificEpithet().equals("")){
665 fltq
.addTerms(nvn
.getInfraSpecificEpithet().toLowerCase(), "infraSpecificEpithet", accuracy
, 3);
667 //textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
668 textQuery
.add(queryFactory
.newTermQuery("infraSpecificEpithet", "_null_", false), Occur
.MUST
);
671 if(nvn
.getAuthorshipCache() != null && !nvn
.getAuthorshipCache().equals("")){
672 fltq
.addTerms(nvn
.getAuthorshipCache().toLowerCase(), "authorshipCache", accuracy
, 3);
674 //textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);
677 textQuery
.add(fltq
, Occur
.MUST
);
679 finalQuery
.add(textQuery
, Occur
.MUST
);
681 luceneSearch
.setQuery(finalQuery
);
683 if(highlightFragments
){
684 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
689 protected LuceneSearch
prepareFindByFuzzyNameCacheSearch(Class
<?
extends CdmBase
> clazz
,
693 List
<Language
> languages
,
694 boolean highlightFragments
) {
696 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
697 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
699 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
700 // luceneSearch.setSortFields(sortFields);
702 // ---- search criteria
703 luceneSearch
.setCdmTypRestriction(clazz
);
704 FuzzyLikeThisQuery fltq
= new FuzzyLikeThisQuery(maxNoOfResults
, luceneSearch
.getAnalyzer());
706 fltq
.addTerms(name
, "nameCache", accuracy
, 3);
708 BooleanQuery finalQuery
= new BooleanQuery(false);
710 finalQuery
.add(fltq
, Occur
.MUST
);
712 luceneSearch
.setQuery(finalQuery
);
714 if(highlightFragments
){
715 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
720 protected LuceneSearch
prepareFindByExactNameSearch(Class
<?
extends CdmBase
> clazz
,
723 List
<Language
> languages
,
724 boolean highlightFragments
) {
725 BooleanQuery finalQuery
= new BooleanQuery();
726 BooleanQuery textQuery
= new BooleanQuery();
728 LuceneSearch luceneSearch
= new LuceneSearch(luceneIndexToolProvider
, TaxonNameBase
.class);
729 QueryFactory queryFactory
= luceneIndexToolProvider
.newQueryFactoryFor(TaxonNameBase
.class);
731 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
732 // luceneSearch.setSortFields(sortFields);
734 // ---- search criteria
735 luceneSearch
.setCdmTypRestriction(clazz
);
737 if(name
!= null && !name
.equals("")) {
739 textQuery
.add(new WildcardQuery(new Term("nameCache", name
+ "*")), Occur
.MUST
);
741 textQuery
.add(queryFactory
.newTermQuery("nameCache", name
, false), Occur
.MUST
);
745 luceneSearch
.setQuery(textQuery
);
747 if(highlightFragments
){
748 luceneSearch
.setHighlightFields(queryFactory
.getTextFieldNamesAsArray());
754 public List
<SearchResult
<TaxonNameBase
>> findByNameFuzzySearch(
757 List
<Language
> languages
,
758 boolean highlightFragments
,
759 List
<String
> propertyPaths
,
760 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
762 logger
.info("Name to fuzzy search for : " + name
);
763 // parse the input name
764 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
765 NonViralName nvn
= parser
.parseFullName(name
);
766 if(name
!= null && !name
.equals("") && nvn
== null) {
767 throw new ParseException("Could not parse name " + name
);
769 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
771 // --- execute search
772 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
775 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
776 idFieldMap
.put(CdmBaseType
.NONVIRALNAME
, "id");
778 // --- initialize taxa, highlight matches ....
779 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
781 @SuppressWarnings("rawtypes")
782 List
<SearchResult
<TaxonNameBase
>> searchResults
= searchResultBuilder
.createResultSet(
783 topDocs
, luceneSearch
.getHighlightFields(), dao
, idFieldMap
, propertyPaths
);
785 return searchResults
;
790 public List
<DocumentSearchResult
> findByNameFuzzySearch(
793 List
<Language
> languages
,
794 boolean highlightFragments
,
795 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
797 logger
.info("Name to fuzzy search for : " + name
);
798 // parse the input name
799 NonViralNameParserImpl parser
= new NonViralNameParserImpl();
800 NonViralName nvn
= parser
.parseFullName(name
);
801 if(name
!= null && !name
.equals("") && nvn
== null) {
802 throw new ParseException("Could not parse name " + name
);
804 LuceneSearch luceneSearch
= prepareFindByFuzzyNameSearch(null, nvn
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
806 // --- execute search
807 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
809 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
811 // --- initialize taxa, highlight matches ....
812 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
814 @SuppressWarnings("rawtypes")
815 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
817 return searchResults
;
821 public List
<DocumentSearchResult
> findByFuzzyNameCacheSearch(
824 List
<Language
> languages
,
825 boolean highlightFragments
,
826 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
828 logger
.info("Name to fuzzy search for : " + name
);
830 LuceneSearch luceneSearch
= prepareFindByFuzzyNameCacheSearch(null, name
, accuracy
, maxNoOfResults
, languages
, highlightFragments
);
832 // --- execute search
833 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
834 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
836 // --- initialize taxa, highlight matches ....
837 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
839 @SuppressWarnings("rawtypes")
840 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
842 return searchResults
;
846 public List
<DocumentSearchResult
> findByNameExactSearch(
849 List
<Language
> languages
,
850 boolean highlightFragments
,
851 int maxNoOfResults
) throws CorruptIndexException
, IOException
, ParseException
{
853 logger
.info("Name to exact search for : " + name
);
855 LuceneSearch luceneSearch
= prepareFindByExactNameSearch(null, name
, wildcard
, languages
, highlightFragments
);
857 // --- execute search
860 TopDocs topDocs
= luceneSearch
.executeSearch(maxNoOfResults
);
862 Map
<CdmBaseType
, String
> idFieldMap
= new HashMap
<CdmBaseType
, String
>();
864 // --- initialize taxa, highlight matches ....
865 ISearchResultBuilder searchResultBuilder
= new SearchResultBuilder(luceneSearch
, luceneSearch
.getQuery());
867 @SuppressWarnings("rawtypes")
868 List
<DocumentSearchResult
> searchResults
= searchResultBuilder
.createResultSet(topDocs
, luceneSearch
.getHighlightFields());
870 return searchResults
;
874 * @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)
877 public Pager
<NameRelationship
> pageNameRelationships(TaxonNameBase name
, Direction direction
, NameRelationshipType type
, Integer pageSize
,
878 Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
879 List
<NameRelationship
> results
= listNameRelationships(name
, direction
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
880 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
884 public List
<NameRelationship
> listFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
885 return listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
889 public Pager
<NameRelationship
> pageFromNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
890 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedFrom
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
891 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
895 public List
<NameRelationship
> listToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
896 return listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
900 public Pager
<NameRelationship
> pageToNameRelationships(TaxonNameBase name
, NameRelationshipType type
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
, List
<String
> propertyPaths
) {
901 List
<NameRelationship
> results
= listNameRelationships(name
, Direction
.relatedTo
, type
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
902 return new DefaultPagerImpl
<NameRelationship
>(pageNumber
, results
.size(), pageSize
, results
);
906 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
907 Integer pageSize
, Integer pageNumber
) {
908 return getTypeDesignations(name
, status
, pageSize
, pageNumber
, null);
912 public Pager
<TypeDesignationBase
> getTypeDesignations(TaxonNameBase name
, SpecimenTypeDesignationStatus status
,
913 Integer pageSize
, Integer pageNumber
, List
<String
> propertyPaths
){
914 Integer numberOfResults
= dao
.countTypeDesignations(name
, status
);
916 List
<TypeDesignationBase
> results
= new ArrayList
<TypeDesignationBase
>();
917 if(AbstractPagerImpl
.hasResultsInRange(numberOfResults
.longValue(), pageNumber
, pageSize
)) {
918 results
= dao
.getTypeDesignations(name
, null, status
, pageSize
, pageNumber
, propertyPaths
);
921 return new DefaultPagerImpl
<TypeDesignationBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
925 * FIXME Candidate for harmonization
929 public Pager
<TaxonNameBase
> searchNames(String uninomial
,String infraGenericEpithet
, String specificEpithet
, String infraspecificEpithet
, Rank rank
, Integer pageSize
, Integer pageNumber
, List
<OrderHint
> orderHints
,
930 List
<String
> propertyPaths
) {
931 Integer numberOfResults
= dao
.countNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
);
933 List
<TaxonNameBase
> results
= new ArrayList
<TaxonNameBase
>();
934 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
935 results
= dao
.searchNames(uninomial
, infraGenericEpithet
, specificEpithet
, infraspecificEpithet
, rank
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
938 return new DefaultPagerImpl
<TaxonNameBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
942 * @see eu.etaxonomy.cdm.api.service.INameService#getUuidAndTitleCacheOfNames()
945 public List
<UuidAndTitleCache
> getUuidAndTitleCacheOfNames() {
946 return dao
.getUuidAndTitleCacheOfNames();
950 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
) {
951 Integer numberOfResults
= dao
.countByName(clazz
, queryString
, matchmode
, criteria
);
953 List
<TaxonNameBase
> results
= new ArrayList
<TaxonNameBase
>();
954 if(numberOfResults
> 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
955 results
= dao
.findByName(clazz
, queryString
, matchmode
, criteria
, pageSize
, pageNumber
, orderHints
, propertyPaths
);
958 return new DefaultPagerImpl
<TaxonNameBase
>(pageNumber
, numberOfResults
, pageSize
, results
);
962 public HomotypicalGroup
findHomotypicalGroup(UUID uuid
) {
963 return homotypicalGroupDao
.findByUuid(uuid
);
968 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
971 @Transactional(readOnly
= false)
972 public void updateTitleCache(Class
<?
extends TaxonNameBase
> clazz
, Integer stepSize
, IIdentifiableEntityCacheStrategy
<TaxonNameBase
> cacheStrategy
, IProgressMonitor monitor
) {
974 clazz
= TaxonNameBase
.class;
976 super.updateTitleCacheImpl(clazz
, stepSize
, cacheStrategy
, monitor
);
981 protected void setOtherCachesNull(TaxonNameBase name
) {
982 if (name
.isInstanceOf(NonViralName
.class)){
983 NonViralName
<?
> nvn
= CdmBase
.deproxy(name
, NonViralName
.class);
984 if (! nvn
.isProtectedNameCache()){
985 nvn
.setNameCache(null, false);
987 if (! nvn
.isProtectedAuthorshipCache()){
988 nvn
.setAuthorshipCache(null, false);
990 if (! nvn
.isProtectedFullTitleCache()){
991 nvn
.setFullTitleCache(null, false);
997 * @see eu.etaxonomy.cdm.api.service.INameService#getTaggedName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
1000 public List
<TaggedText
> getTaggedName(UUID uuid
) {
1001 TaxonNameBase taxonNameBase
= dao
.load(uuid
);
1002 List taggedName
= taxonNameBase
.getTaggedName();
1007 public List
<String
> isDeletable(TaxonNameBase name
, DeleteConfiguratorBase config
){
1008 List
<String
> result
= new ArrayList
<String
>();
1009 name
= (TaxonNameBase
)HibernateProxyHelper
.deproxy(name
);
1010 NameDeletionConfigurator nameConfig
= null;
1011 if (config
instanceof NameDeletionConfigurator
){
1012 nameConfig
= (NameDeletionConfigurator
) config
;
1014 result
.add("The delete configurator should be of the type NameDeletionConfigurator.");
1018 if (!name
.getNameRelations().isEmpty() && !nameConfig
.isRemoveAllNameRelationships()){
1019 if (!nameConfig
.isIgnoreIsBasionymFor() && name
.isGroupsBasionym()){
1020 String message
= "Name can't be deleted as it is a basionym.";
1021 result
.add(message
);
1023 if (!nameConfig
.isIgnoreHasBasionym() && (name
.getBasionyms().size()>0)){
1024 String message
= "Name can't be deleted as it has a basionym.";
1025 result
.add(message
);
1027 Set
<NameRelationship
> relationships
= name
.getNameRelations();
1028 for (NameRelationship rel
: relationships
){
1029 if (!rel
.getType().equals(NameRelationshipType
.BASIONYM())){
1030 String message
= "Name can't be deleted as it is used in name relationship(s). Remove name relationships prior to deletion.";
1031 result
.add(message
);
1040 if (! name
.getTaxonBases().isEmpty()){
1041 String message
= "Name can't be deleted as it is used in concept(s). Remove or change concept prior to deletion.";
1042 result
.add(message
);
1045 //hybrid relationships
1046 if (name
.isInstanceOf(NonViralName
.class)){
1047 NonViralName nvn
= CdmBase
.deproxy(name
, NonViralName
.class);
1048 if (! nvn
.getHybridParentRelations().isEmpty()){
1049 String message
= "Name can't be deleted as it is a parent in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
1050 result
.add(message
);
1053 Set
<CdmBase
> referencingObjects
= genericDao
.getReferencingObjects(name
);
1054 for (CdmBase referencingObject
: referencingObjects
){
1055 //DerivedUnit?.storedUnder
1056 if (referencingObject
.isInstanceOf(DerivedUnit
.class)){
1057 String message
= "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";
1058 message
= String
.format(message
, CdmBase
.deproxy(referencingObject
, DerivedUnit
.class).getTitleCache());
1059 result
.add(message
);
1061 //DescriptionElementSource#nameUsedInSource
1062 if (referencingObject
.isInstanceOf(DescriptionElementSource
.class)){
1063 String message
= "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";
1064 result
.add(message
);
1066 //NameTypeDesignation#typeName
1067 if (referencingObject
.isInstanceOf(NameTypeDesignation
.class)){
1068 String message
= "Name can't be deleted as it is used as a name type in a NameTypeDesignation";
1069 result
.add(message
);
1076 //TODO inline references
1079 if (!nameConfig
.isIgnoreIsReplacedSynonymFor() && name
.isReplacedSynonym()){
1080 String message
= "Name can't be deleted as it is a replaced synonym.";
1081 result
.add(message
);
1083 if (!nameConfig
.isIgnoreHasReplacedSynonym() && (name
.getReplacedSynonyms().size()>0)){
1084 String message
= "Name can't be deleted as it has a replaced synonym.";
1085 result
.add(message
);