Major Update to cdmlib-3.3
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / NameServiceImpl.java
1 // $Id$
2 /**
3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
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.
9 */
10
11 package eu.etaxonomy.cdm.api.service;
12
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;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.UUID;
22
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;
37
38 import eu.etaxonomy.cdm.api.service.config.NameDeletionConfigurator;
39 import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
40 import eu.etaxonomy.cdm.api.service.pager.Pager;
41 import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
42 import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
43 import eu.etaxonomy.cdm.api.service.search.DocumentSearchResult;
44 import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;
45 import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
46 import eu.etaxonomy.cdm.api.service.search.LuceneSearch;
47 import eu.etaxonomy.cdm.api.service.search.QueryFactory;
48 import eu.etaxonomy.cdm.api.service.search.SearchResult;
49 import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;
50 import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
51 import eu.etaxonomy.cdm.model.CdmBaseType;
52 import eu.etaxonomy.cdm.model.common.CdmBase;
53 import eu.etaxonomy.cdm.model.common.Language;
54 import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
55 import eu.etaxonomy.cdm.model.common.ReferencedEntityBase;
56 import eu.etaxonomy.cdm.model.common.RelationshipBase;
57 import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
58 import eu.etaxonomy.cdm.model.common.TermVocabulary;
59 import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;
60 import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
61 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
62 import eu.etaxonomy.cdm.model.name.HybridRelationship;
63 import eu.etaxonomy.cdm.model.name.HybridRelationshipType;
64 import eu.etaxonomy.cdm.model.name.NameRelationship;
65 import eu.etaxonomy.cdm.model.name.NameRelationshipType;
66 import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
67 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
68 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
69 import eu.etaxonomy.cdm.model.name.NonViralName;
70 import eu.etaxonomy.cdm.model.name.Rank;
71 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
72 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
73 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
74 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
75 import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
76 import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao;
77 import eu.etaxonomy.cdm.persistence.dao.common.IReferencedEntityDao;
78 import eu.etaxonomy.cdm.persistence.dao.common.ITermVocabularyDao;
79 import eu.etaxonomy.cdm.persistence.dao.name.IHomotypicalGroupDao;
80 import eu.etaxonomy.cdm.persistence.dao.name.INomenclaturalStatusDao;
81 import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
82 import eu.etaxonomy.cdm.persistence.dao.name.ITypeDesignationDao;
83 import eu.etaxonomy.cdm.persistence.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;
88
89
90 @Service
91 @Transactional(readOnly = true)
92 public class NameServiceImpl extends IdentifiableServiceBase<TaxonNameBase,ITaxonNameDao> implements INameService {
93 static private final Logger logger = Logger.getLogger(NameServiceImpl.class);
94
95 @Autowired
96 protected ITermVocabularyDao vocabularyDao;
97 @Autowired
98 protected IOrderedTermVocabularyDao orderedVocabularyDao;
99 @Autowired
100 @Qualifier("refEntDao")
101 protected IReferencedEntityDao<ReferencedEntityBase> referencedEntityDao;
102 @Autowired
103 private INomenclaturalStatusDao nomStatusDao;
104 @Autowired
105 private ITypeDesignationDao typeDesignationDao;
106 @Autowired
107 private IHomotypicalGroupDao homotypicalGroupDao;
108 @Autowired
109 private ICdmGenericDao genericDao;
110 @Autowired
111 private ILuceneIndexToolProvider luceneIndexToolProvider;
112
113 /**
114 * Constructor
115 */
116 public NameServiceImpl(){
117 if (logger.isDebugEnabled()) { logger.debug("Load NameService Bean"); }
118 }
119
120 //********************* METHODS ****************************************************************//
121
122 /* (non-Javadoc)
123 * @see eu.etaxonomy.cdm.api.service.ServiceBase#delete(eu.etaxonomy.cdm.model.common.CdmBase)
124 */
125 @Override
126 public UUID delete(TaxonNameBase name){
127 NameDeletionConfigurator config = new NameDeletionConfigurator();
128 try {
129 return delete(name, config);
130 } catch (ReferencedObjectUndeletableException e) {
131 //TODO throw DeleteException - current implementation is preliminary for testing
132 throw new RuntimeException(e);
133 }
134 }
135
136 /* (non-Javadoc)
137 * @see eu.etaxonomy.cdm.api.service.INameService#delete(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.api.service.NameDeletionConfigurator)
138 */
139 @Override
140 public UUID delete(TaxonNameBase name, NameDeletionConfigurator config) throws ReferencedObjectUndeletableException{
141 if (name == null){
142 return null;
143 }
144
145 //remove references to this name
146 removeNameRelationshipsByDeleteConfig(name, config);
147
148 //check if this name is still used somewhere
149
150 //name relationships
151 if (! name.getNameRelations().isEmpty()){
152 String message = "Name can't be deleted as it is used in name relationship(s). Remove name relationships prior to deletion.";
153 throw new ReferencedObjectUndeletableException(message);
154 // return null;
155 }
156
157 //concepts
158 if (! name.getTaxonBases().isEmpty()){
159 String message = "Name can't be deleted as it is used in concept(s). Remove or change concept prior to deletion.";
160 throw new ReferencedObjectUndeletableException(message);
161 }
162
163 //hybrid relationships
164 if (name.isInstanceOf(NonViralName.class)){
165 NonViralName nvn = CdmBase.deproxy(name, NonViralName.class);
166 // if (! nvn.getHybridChildRelations().isEmpty()){
167 // String message = "Name can't be deleted as it is a child in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
168 // throw new RuntimeException(message);
169 // }
170 if (! nvn.getHybridParentRelations().isEmpty()){
171 String message = "Name can't be deleted as it is a parent in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
172 throw new ReferencedObjectUndeletableException(message);
173 }
174 }
175
176 //all type designation relationships are removed as they belong to the name
177 deleteTypeDesignation(name, null);
178 // //type designations
179 // if (! name.getTypeDesignations().isEmpty()){
180 // String message = "Name can't be deleted as it has types. Remove types prior to deletion.";
181 // throw new ReferrencedObjectUndeletableException(message);
182 // }
183
184 //check references with only reverse mapping
185 Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(name);
186 for (CdmBase referencingObject : referencingObjects){
187 //DerivedUnit?.storedUnder
188 if (referencingObject.isInstanceOf(DerivedUnit.class)){
189 String message = "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";
190 message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnit.class).getTitleCache());
191 throw new ReferencedObjectUndeletableException(message);
192 }
193 //DescriptionElementSource#nameUsedInSource
194 if (referencingObject.isInstanceOf(DescriptionElementSource.class)){
195 String message = "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";
196 throw new ReferencedObjectUndeletableException(message);
197 }
198 //NameTypeDesignation#typeName
199 if (referencingObject.isInstanceOf(NameTypeDesignation.class)){
200 String message = "Name can't be deleted as it is used as a name type in a NameTypeDesignation";
201 throw new ReferencedObjectUndeletableException(message);
202 }
203
204 //TaxonNameDescriptions#taxonName
205 //deleted via cascade?
206
207 //NomenclaturalStatus
208 //deleted via cascade?
209
210 }
211
212 //TODO inline references
213
214 dao.delete(name);
215 return name.getUuid();
216 }
217
218 /* (non-Javadoc)
219 * @see eu.etaxonomy.cdm.api.service.INameService#deleteTypeDesignation(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.model.name.TypeDesignationBase)
220 */
221 @Override
222 public void deleteTypeDesignation(TaxonNameBase name, TypeDesignationBase typeDesignation){
223 if (name == null && typeDesignation == null){
224 return;
225 }else if (name != null && typeDesignation != null){
226 removeSingleDesignation(name, typeDesignation);
227 }else if (name != null){
228 Set<TypeDesignationBase> designationSet = new HashSet<TypeDesignationBase>(name.getTypeDesignations());
229 for (Object o : designationSet){
230 TypeDesignationBase desig = CdmBase.deproxy(o, TypeDesignationBase.class);
231 removeSingleDesignation(name, desig);
232 }
233 }else if (typeDesignation != null){
234 Set<TaxonNameBase> nameSet = new HashSet<TaxonNameBase>(typeDesignation.getTypifiedNames());
235 for (Object o : nameSet){
236 TaxonNameBase singleName = CdmBase.deproxy(o, TaxonNameBase.class);
237 removeSingleDesignation(singleName, typeDesignation);
238 }
239 }
240 }
241
242 /**
243 * @param name
244 * @param typeDesignation
245 */
246 private void removeSingleDesignation(TaxonNameBase name, TypeDesignationBase typeDesignation) {
247 name.removeTypeDesignation(typeDesignation);
248 if (typeDesignation.getTypifiedNames().isEmpty()){
249 typeDesignation.removeType();
250 typeDesignationDao.delete(typeDesignation);
251 }
252 }
253
254
255
256 /**
257 * @param name
258 * @param config
259 */
260 private void removeNameRelationshipsByDeleteConfig(TaxonNameBase name, NameDeletionConfigurator config) {
261 if (config.isRemoveAllNameRelationships()){
262 Set<NameRelationship> rels = name.getNameRelations();
263 for (NameRelationship rel : rels){
264 name.removeNameRelationship(rel);
265 }
266 }else{
267 //relations to this name
268 Set<NameRelationship> rels = name.getRelationsToThisName();
269 for (NameRelationship rel : rels){
270 if (config.isIgnoreHasBasionym() && NameRelationshipType.BASIONYM().equals(rel.getType() )){
271 name.removeNameRelationship(rel);
272 }else if (config.isIgnoreHasReplacedSynonym() && NameRelationshipType.REPLACED_SYNONYM().equals(rel.getType())){
273 name.removeNameRelationship(rel);
274 }
275 }
276 //relations from this name
277 rels = name.getRelationsFromThisName();
278 for (NameRelationship rel : rels){
279 if (config.isIgnoreIsBasionymFor() && NameRelationshipType.BASIONYM().equals(rel.getType()) ){
280 name.removeNameRelationship(rel);
281 }else if (config.isIgnoreIsReplacedSynonymFor() && NameRelationshipType.REPLACED_SYNONYM().equals(rel.getType())){
282 name.removeNameRelationship(rel);
283 }
284 }
285
286 }
287 }
288
289 //********************* METHODS ****************************************************************//
290
291 /**
292 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
293 * duplicate of findByName
294 */
295 @Override
296 @Deprecated
297 public List getNamesByName(String name){
298 return super.findCdmObjectsByTitle(name);
299 }
300
301 /**
302 * TODO candidate for harmonization
303 * new name findByName
304 */
305 @Override
306 public List<NonViralName> getNamesByNameCache(String nameCache){
307 List result = dao.findByName(nameCache, MatchMode.EXACT, null, null, null, null);
308 return result;
309 }
310
311
312 /**
313 * TODO candidate for harmonization
314 * new name saveHomotypicalGroups
315 *
316 * findByTitle
317 */
318 @Override
319 public List<NonViralName> findNamesByTitleCache(String titleCache, MatchMode matchMode, List<String> propertyPaths){
320 List result = dao.findByTitle(titleCache, matchMode, null, null, null ,propertyPaths);
321 return result;
322 }
323
324 /**
325 * TODO candidate for harmonization
326 * new name saveHomotypicalGroups
327 *
328 * findByTitle
329 */
330 @Override
331 public List<NonViralName> findNamesByNameCache(String nameCache, MatchMode matchMode, List<String> propertyPaths){
332 List result = dao.findByName(nameCache, matchMode, null, null, null ,propertyPaths);
333 return result;
334 }
335
336 /**
337 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
338 * Replace by load(UUID, propertyPaths)
339 */
340 @Override
341 @Deprecated
342 public NonViralName findNameByUuid(UUID uuid, List<String> propertyPaths){
343 return (NonViralName)dao.findByUuid(uuid, null ,propertyPaths);
344 }
345
346 /**
347 * TODO candidate for harmonization
348 */
349 @Override
350 public List getNamesByName(String name, CdmBase sessionObject){
351 return super.findCdmObjectsByTitle(name, sessionObject);
352 }
353
354 /**
355 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
356 * duplicate of findByTitle(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths)
357 */
358 @Override
359 @Deprecated
360 public List findNamesByTitle(String title){
361 return super.findCdmObjectsByTitle(title);
362 }
363
364 /**
365 * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
366 * duplicate of findByTitle()
367 */
368 @Override
369 @Deprecated
370 public List findNamesByTitle(String title, CdmBase sessionObject){
371 return super.findCdmObjectsByTitle(title, sessionObject);
372 }
373
374 /**
375 * TODO candidate for harmonization
376 * new name saveHomotypicalGroups
377 */
378 @Override
379 @Transactional(readOnly = false)
380 public Map<UUID, HomotypicalGroup> saveAllHomotypicalGroups(Collection<HomotypicalGroup> homotypicalGroups){
381 return homotypicalGroupDao.saveAll(homotypicalGroups);
382 }
383
384 /**
385 * TODO candidate for harmonization
386 * new name saveTypeDesignations
387 */
388 @Override
389 @Transactional(readOnly = false)
390 public Map<UUID, TypeDesignationBase> saveTypeDesignationAll(Collection<TypeDesignationBase> typeDesignationCollection){
391 return typeDesignationDao.saveAll(typeDesignationCollection);
392 }
393
394 /**
395 * TODO candidate for harmonization
396 * new name saveReferencedEntities
397 */
398 @Override
399 @Transactional(readOnly = false)
400 public Map<UUID, ReferencedEntityBase> saveReferencedEntitiesAll(Collection<ReferencedEntityBase> referencedEntityCollection){
401 return referencedEntityDao.saveAll(referencedEntityCollection);
402 }
403
404 /**
405 * TODO candidate for harmonization
406 * new name getNames
407 */
408 public List<TaxonNameBase> getAllNames(int limit, int start){
409 return dao.list(limit, start);
410 }
411
412 /**
413 * TODO candidate for harmonization
414 * new name getNomenclaturalStatus
415 */
416 @Override
417 public List<NomenclaturalStatus> getAllNomenclaturalStatus(int limit, int start){
418 return nomStatusDao.list(limit, start);
419 }
420
421 /**
422 * TODO candidate for harmonization
423 * new name getTypeDesignations
424 */
425 @Override
426 public List<TypeDesignationBase> getAllTypeDesignations(int limit, int start){
427 return typeDesignationDao.getAllTypeDesignations(limit, start);
428 }
429 /**
430 * FIXME Candidate for harmonization
431 * homotypicalGroupService.list
432 */
433 @Override
434 public List<HomotypicalGroup> getAllHomotypicalGroups(int limit, int start){
435 return homotypicalGroupDao.list(limit, start);
436 }
437
438 /**
439 * FIXME Candidate for harmonization
440 * remove
441 */
442 @Override
443 @Deprecated
444 public List<RelationshipBase> getAllRelationships(int limit, int start){
445 return dao.getAllRelationships(limit, start);
446 }
447
448 /**
449 * FIXME Candidate for harmonization
450 * is this not the same as termService.getVocabulary(VocabularyEnum.Rank)
451 * since this returns OrderedTermVocabulary
452 *
453 * (non-Javadoc)
454 * @see eu.etaxonomy.cdm.api.service.INameService#getRankVocabulary()
455 */
456 @Override
457 public OrderedTermVocabulary<Rank> getRankVocabulary() {
458 String uuidString = "ef0d1ce1-26e3-4e83-b47b-ca74eed40b1b";
459 UUID uuid = UUID.fromString(uuidString);
460 OrderedTermVocabulary<Rank> rankVocabulary =
461 (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
462 return rankVocabulary;
463 }
464
465 /**
466 * FIXME Candidate for harmonization
467 * is this the same as termService.getVocabulary(VocabularyEnum.NameRelationshipType)
468 * (non-Javadoc)
469 * @see eu.etaxonomy.cdm.api.service.INameService#getNameRelationshipTypeVocabulary()
470 */
471 @Override
472 public TermVocabulary<NameRelationshipType> getNameRelationshipTypeVocabulary() {
473 String uuidString = "6878cb82-c1a4-4613-b012-7e73b413c8cd";
474 UUID uuid = UUID.fromString(uuidString);
475 TermVocabulary<NameRelationshipType> nameRelTypeVocabulary =
476 vocabularyDao.findByUuid(uuid);
477 return nameRelTypeVocabulary;
478 }
479
480 /**
481 * FIXME Candidate for harmonization
482 * is this the same as termService.getVocabulary(VocabularyEnum.StatusType)
483 * (non-Javadoc)
484 * @see eu.etaxonomy.cdm.api.service.INameService#getStatusTypeVocabulary()
485 */
486 @Override
487 public TermVocabulary<NomenclaturalStatusType> getStatusTypeVocabulary() {
488 String uuidString = "bb28cdca-2f8a-4f11-9c21-517e9ae87f1f";
489 UUID uuid = UUID.fromString(uuidString);
490 TermVocabulary<NomenclaturalStatusType> nomStatusTypeVocabulary =
491 vocabularyDao.findByUuid(uuid);
492 return nomStatusTypeVocabulary;
493 }
494
495 /**
496 * FIXME Candidate for harmonization
497 * is this the same as termService.getVocabulary(VocabularyEnum.SpecimenTypeDesignationStatus)
498 * (non-Javadoc)
499 * @see eu.etaxonomy.cdm.api.service.INameService#getTypeDesignationStatusVocabulary()
500 */
501 @Override
502 public TermVocabulary<SpecimenTypeDesignationStatus> getSpecimenTypeDesignationStatusVocabulary() {
503 String uuidString = "ab177bd7-d3c8-4e58-a388-226fff6ba3c2";
504 UUID uuid = UUID.fromString(uuidString);
505 TermVocabulary<SpecimenTypeDesignationStatus> typeDesigStatusVocabulary =
506 vocabularyDao.findByUuid(uuid);
507 return typeDesigStatusVocabulary;
508 }
509
510 /**
511 * FIXME Candidate for harmonization
512 * is this the same as termService.getVocabulary(VocabularyEnum.SpecimenTypeDesignationStatus)
513 * and also seems to duplicate the above method, differing only in the DAO used and the return type
514 * (non-Javadoc)
515 * @see eu.etaxonomy.cdm.api.service.INameService#getTypeDesignationStatusVocabulary()
516 */
517 @Override
518 public OrderedTermVocabulary<SpecimenTypeDesignationStatus> getSpecimenTypeDesignationVocabulary() {
519 String uuidString = "ab177bd7-d3c8-4e58-a388-226fff6ba3c2";
520 UUID uuid = UUID.fromString(uuidString);
521 OrderedTermVocabulary<SpecimenTypeDesignationStatus> typeDesignationVocabulary =
522 (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
523 return typeDesignationVocabulary;
524 }
525
526
527 @Override
528 @Autowired
529 protected void setDao(ITaxonNameDao dao) {
530 this.dao = dao;
531 }
532
533 @Override
534 public Pager<HybridRelationship> getHybridNames(NonViralName name, HybridRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
535 Integer numberOfResults = dao.countHybridNames(name, type);
536
537 List<HybridRelationship> results = new ArrayList<HybridRelationship>();
538 if(AbstractPagerImpl.hasResultsInRange(numberOfResults.longValue(), pageNumber, pageSize)) { // no point checking again
539 results = dao.getHybridNames(name, type, pageSize, pageNumber,orderHints,propertyPaths);
540 }
541
542 return new DefaultPagerImpl<HybridRelationship>(pageNumber, numberOfResults, pageSize, results);
543 }
544
545 /* (non-Javadoc)
546 * @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)
547 */
548 @Override
549 public List<NameRelationship> listNameRelationships(TaxonNameBase name, Direction direction, NameRelationshipType type, Integer pageSize,
550 Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
551
552 Integer numberOfResults = dao.countNameRelationships(name, NameRelationship.Direction.relatedFrom, type);
553
554 List<NameRelationship> results = new ArrayList<NameRelationship>();
555 if (AbstractPagerImpl.hasResultsInRange(numberOfResults.longValue(), pageNumber, pageSize)) { // no point checking again
556 results = dao.getNameRelationships(name, direction, type, pageSize, pageNumber, orderHints, propertyPaths);
557 }
558 return results;
559 }
560
561
562 protected LuceneSearch prepareFindByFuzzyNameSearch(Class<? extends CdmBase> clazz,
563 NonViralName nvn,
564 float accuracy,
565 int maxNoOfResults,
566 List<Language> languages,
567 boolean highlightFragments) {
568 String similarity = Float.toString(accuracy);
569 String searchSuffix = "~" + similarity;
570
571
572 BooleanQuery finalQuery = new BooleanQuery(false);
573 BooleanQuery textQuery = new BooleanQuery(false);
574
575 LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, TaxonNameBase.class);
576 QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonNameBase.class);
577
578 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
579 // luceneSearch.setSortFields(sortFields);
580
581 // ---- search criteria
582 luceneSearch.setCdmTypRestriction(clazz);
583
584 FuzzyLikeThisQuery fltq = new FuzzyLikeThisQuery(maxNoOfResults, luceneSearch.getAnalyzer());
585 if(nvn.getGenusOrUninomial() != null && !nvn.getGenusOrUninomial().equals("")) {
586 fltq.addTerms(nvn.getGenusOrUninomial().toLowerCase(), "genusOrUninomial", accuracy, 3);
587 } else {
588 //textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);
589 textQuery.add(queryFactory.newTermQuery("genusOrUninomial", "_null_", false), Occur.MUST);
590 }
591
592 if(nvn.getInfraGenericEpithet() != null && !nvn.getInfraGenericEpithet().equals("")){
593 fltq.addTerms(nvn.getInfraGenericEpithet().toLowerCase(), "infraGenericEpithet", accuracy, 3);
594 } else {
595 //textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
596 textQuery.add(queryFactory.newTermQuery("infraGenericEpithet", "_null_", false), Occur.MUST);
597 }
598
599 if(nvn.getSpecificEpithet() != null && !nvn.getSpecificEpithet().equals("")){
600 fltq.addTerms(nvn.getSpecificEpithet().toLowerCase(), "specificEpithet", accuracy, 3);
601 } else {
602 //textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
603 textQuery.add(queryFactory.newTermQuery("specificEpithet", "_null_", false), Occur.MUST);
604 }
605
606 if(nvn.getInfraSpecificEpithet() != null && !nvn.getInfraSpecificEpithet().equals("")){
607 fltq.addTerms(nvn.getInfraSpecificEpithet().toLowerCase(), "infraSpecificEpithet", accuracy, 3);
608 } else {
609 //textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
610 textQuery.add(queryFactory.newTermQuery("infraSpecificEpithet", "_null_", false), Occur.MUST);
611 }
612
613 if(nvn.getAuthorshipCache() != null && !nvn.getAuthorshipCache().equals("")){
614 fltq.addTerms(nvn.getAuthorshipCache().toLowerCase(), "authorshipCache", accuracy, 3);
615 } else {
616 //textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);
617 }
618
619 textQuery.add(fltq, Occur.MUST);
620
621 finalQuery.add(textQuery, Occur.MUST);
622
623 luceneSearch.setQuery(finalQuery);
624
625 if(highlightFragments){
626 luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
627 }
628 return luceneSearch;
629 }
630
631 protected LuceneSearch prepareFindByFuzzyNameCacheSearch(Class<? extends CdmBase> clazz,
632 String name,
633 float accuracy,
634 int maxNoOfResults,
635 List<Language> languages,
636 boolean highlightFragments) {
637
638 LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, TaxonNameBase.class);
639 QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonNameBase.class);
640
641 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
642 // luceneSearch.setSortFields(sortFields);
643
644 // ---- search criteria
645 luceneSearch.setCdmTypRestriction(clazz);
646 FuzzyLikeThisQuery fltq = new FuzzyLikeThisQuery(maxNoOfResults, luceneSearch.getAnalyzer());
647
648 fltq.addTerms(name, "nameCache", accuracy, 3);
649
650 BooleanQuery finalQuery = new BooleanQuery(false);
651
652 finalQuery.add(fltq, Occur.MUST);
653
654 luceneSearch.setQuery(finalQuery);
655
656 if(highlightFragments){
657 luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
658 }
659 return luceneSearch;
660 }
661
662 protected LuceneSearch prepareFindByExactNameSearch(Class<? extends CdmBase> clazz,
663 String name,
664 boolean wildcard,
665 List<Language> languages,
666 boolean highlightFragments) {
667 BooleanQuery finalQuery = new BooleanQuery();
668 BooleanQuery textQuery = new BooleanQuery();
669
670 LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, TaxonNameBase.class);
671 QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(TaxonNameBase.class);
672
673 // SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
674 // luceneSearch.setSortFields(sortFields);
675
676 // ---- search criteria
677 luceneSearch.setCdmTypRestriction(clazz);
678
679 if(name != null && !name.equals("")) {
680 if(wildcard) {
681 textQuery.add(new WildcardQuery(new Term("nameCache", name + "*")), Occur.MUST);
682 } else {
683 textQuery.add(queryFactory.newTermQuery("nameCache", name, false), Occur.MUST);
684 }
685 }
686
687 luceneSearch.setQuery(textQuery);
688
689 if(highlightFragments){
690 luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
691 }
692 return luceneSearch;
693 }
694
695 @Override
696 public List<SearchResult<TaxonNameBase>> findByNameFuzzySearch(
697 String name,
698 float accuracy,
699 List<Language> languages,
700 boolean highlightFragments,
701 List<String> propertyPaths,
702 int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
703
704 logger.info("Name to fuzzy search for : " + name);
705 // parse the input name
706 NonViralNameParserImpl parser = new NonViralNameParserImpl();
707 NonViralName nvn = parser.parseFullName(name);
708 if(name != null && !name.equals("") && nvn == null) {
709 throw new ParseException("Could not parse name " + name);
710 }
711 LuceneSearch luceneSearch = prepareFindByFuzzyNameSearch(null, nvn, accuracy, maxNoOfResults, languages, highlightFragments);
712
713 // --- execute search
714 TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
715
716
717 Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
718 idFieldMap.put(CdmBaseType.NONVIRALNAME, "id");
719
720 // --- initialize taxa, highlight matches ....
721 ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
722
723 @SuppressWarnings("rawtypes")
724 List<SearchResult<TaxonNameBase>> searchResults = searchResultBuilder.createResultSet(
725 topDocs, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
726
727 return searchResults;
728
729 }
730
731 @Override
732 public List<DocumentSearchResult> findByNameFuzzySearch(
733 String name,
734 float accuracy,
735 List<Language> languages,
736 boolean highlightFragments,
737 int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
738
739 logger.info("Name to fuzzy search for : " + name);
740 // parse the input name
741 NonViralNameParserImpl parser = new NonViralNameParserImpl();
742 NonViralName nvn = parser.parseFullName(name);
743 if(name != null && !name.equals("") && nvn == null) {
744 throw new ParseException("Could not parse name " + name);
745 }
746 LuceneSearch luceneSearch = prepareFindByFuzzyNameSearch(null, nvn, accuracy, maxNoOfResults, languages, highlightFragments);
747
748 // --- execute search
749 TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
750
751 Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
752
753 // --- initialize taxa, highlight matches ....
754 ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
755
756 @SuppressWarnings("rawtypes")
757 List<DocumentSearchResult> searchResults = searchResultBuilder.createResultSet(topDocs, luceneSearch.getHighlightFields());
758
759 return searchResults;
760 }
761
762 @Override
763 public List<DocumentSearchResult> findByFuzzyNameCacheSearch(
764 String name,
765 float accuracy,
766 List<Language> languages,
767 boolean highlightFragments,
768 int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
769
770 logger.info("Name to fuzzy search for : " + name);
771
772 LuceneSearch luceneSearch = prepareFindByFuzzyNameCacheSearch(null, name, accuracy, maxNoOfResults, languages, highlightFragments);
773
774 // --- execute search
775 TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
776 Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
777
778 // --- initialize taxa, highlight matches ....
779 ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
780
781 @SuppressWarnings("rawtypes")
782 List<DocumentSearchResult> searchResults = searchResultBuilder.createResultSet(topDocs, luceneSearch.getHighlightFields());
783
784 return searchResults;
785 }
786
787 @Override
788 public List<DocumentSearchResult> findByNameExactSearch(
789 String name,
790 boolean wildcard,
791 List<Language> languages,
792 boolean highlightFragments,
793 int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
794
795 logger.info("Name to exact search for : " + name);
796
797 LuceneSearch luceneSearch = prepareFindByExactNameSearch(null, name, wildcard, languages, highlightFragments);
798
799 // --- execute search
800
801
802 TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
803
804 Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
805
806 // --- initialize taxa, highlight matches ....
807 ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
808
809 @SuppressWarnings("rawtypes")
810 List<DocumentSearchResult> searchResults = searchResultBuilder.createResultSet(topDocs, luceneSearch.getHighlightFields());
811
812 return searchResults;
813 }
814
815 /* (non-Javadoc)
816 * @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)
817 */
818 @Override
819 public Pager<NameRelationship> pageNameRelationships(TaxonNameBase name, Direction direction, NameRelationshipType type, Integer pageSize,
820 Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
821 List<NameRelationship> results = listNameRelationships(name, direction, type, pageSize, pageNumber, orderHints, propertyPaths);
822 return new DefaultPagerImpl<NameRelationship>(pageNumber, results.size(), pageSize, results);
823 }
824
825 @Override
826 public List<NameRelationship> listFromNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
827 return listNameRelationships(name, Direction.relatedFrom, type, pageSize, pageNumber, orderHints, propertyPaths);
828 }
829
830 @Override
831 public Pager<NameRelationship> pageFromNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
832 List<NameRelationship> results = listNameRelationships(name, Direction.relatedFrom, type, pageSize, pageNumber, orderHints, propertyPaths);
833 return new DefaultPagerImpl<NameRelationship>(pageNumber, results.size(), pageSize, results);
834 }
835
836 @Override
837 public List<NameRelationship> listToNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
838 return listNameRelationships(name, Direction.relatedTo, type, pageSize, pageNumber, orderHints, propertyPaths);
839 }
840
841 @Override
842 public Pager<NameRelationship> pageToNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
843 List<NameRelationship> results = listNameRelationships(name, Direction.relatedTo, type, pageSize, pageNumber, orderHints, propertyPaths);
844 return new DefaultPagerImpl<NameRelationship>(pageNumber, results.size(), pageSize, results);
845 }
846
847 @Override
848 public Pager<TypeDesignationBase> getTypeDesignations(TaxonNameBase name, SpecimenTypeDesignationStatus status,
849 Integer pageSize, Integer pageNumber) {
850 return getTypeDesignations(name, status, pageSize, pageNumber, null);
851 }
852
853 @Override
854 public Pager<TypeDesignationBase> getTypeDesignations(TaxonNameBase name, SpecimenTypeDesignationStatus status,
855 Integer pageSize, Integer pageNumber, List<String> propertyPaths){
856 Integer numberOfResults = dao.countTypeDesignations(name, status);
857
858 List<TypeDesignationBase> results = new ArrayList<TypeDesignationBase>();
859 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
860 results = dao.getTypeDesignations(name, status, pageSize, pageNumber, propertyPaths);
861 }
862
863 return new DefaultPagerImpl<TypeDesignationBase>(pageNumber, numberOfResults, pageSize, results);
864 }
865
866 /**
867 * FIXME Candidate for harmonization
868 * rename search
869 */
870 @Override
871 public Pager<TaxonNameBase> searchNames(String uninomial,String infraGenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
872 List<String> propertyPaths) {
873 Integer numberOfResults = dao.countNames(uninomial, infraGenericEpithet, specificEpithet, infraspecificEpithet, rank);
874
875 List<TaxonNameBase> results = new ArrayList<TaxonNameBase>();
876 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
877 results = dao.searchNames(uninomial, infraGenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber, orderHints, propertyPaths);
878 }
879
880 return new DefaultPagerImpl<TaxonNameBase>(pageNumber, numberOfResults, pageSize, results);
881 }
882
883 /* (non-Javadoc)
884 * @see eu.etaxonomy.cdm.api.service.INameService#getUuidAndTitleCacheOfNames()
885 */
886 @Override
887 public List<UuidAndTitleCache> getUuidAndTitleCacheOfNames() {
888 return dao.getUuidAndTitleCacheOfNames();
889 }
890
891 @Override
892 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) {
893 Integer numberOfResults = dao.countByName(clazz, queryString, matchmode, criteria);
894
895 List<TaxonNameBase> results = new ArrayList<TaxonNameBase>();
896 if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
897 results = dao.findByName(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);
898 }
899
900 return new DefaultPagerImpl<TaxonNameBase>(pageNumber, numberOfResults, pageSize, results);
901 }
902
903 @Override
904 public HomotypicalGroup findHomotypicalGroup(UUID uuid) {
905 return homotypicalGroupDao.findByUuid(uuid);
906 }
907
908
909 /* (non-Javadoc)
910 * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
911 */
912 @Override
913 @Transactional(readOnly = false)
914 public void updateTitleCache(Class<? extends TaxonNameBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<TaxonNameBase> cacheStrategy, IProgressMonitor monitor) {
915 if (clazz == null){
916 clazz = TaxonNameBase.class;
917 }
918 super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
919 }
920
921
922 @Override
923 protected void setOtherCachesNull(TaxonNameBase name) {
924 if (name.isInstanceOf(NonViralName.class)){
925 NonViralName<?> nvn = CdmBase.deproxy(name, NonViralName.class);
926 if (! nvn.isProtectedNameCache()){
927 nvn.setNameCache(null, false);
928 }
929 if (! nvn.isProtectedAuthorshipCache()){
930 nvn.setAuthorshipCache(null, false);
931 }
932 if (! nvn.isProtectedFullTitleCache()){
933 nvn.setFullTitleCache(null, false);
934 }
935 }
936 }
937
938 /* (non-Javadoc)
939 * @see eu.etaxonomy.cdm.api.service.INameService#getTaggedName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
940 */
941 @Override
942 public List<TaggedText> getTaggedName(UUID uuid) {
943 TaxonNameBase taxonNameBase = dao.load(uuid);
944 List taggedName = taxonNameBase.getTaggedName();
945 return taggedName;
946 }
947
948
949 }