Project

General

Profile

Download (38.5 KB) Statistics
| Branch: | Tag: | Revision:
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.analysis.SimpleAnalyzer;
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.BooleanQuery;
29
import org.apache.lucene.search.Explanation;
30
import org.apache.lucene.search.FuzzyLikeThisQuery;
31
import org.apache.lucene.search.Query;
32
import org.apache.lucene.search.SortField;
33
import org.apache.lucene.search.BooleanClause.Occur;
34
import org.apache.lucene.search.TermQuery;
35
import org.apache.lucene.search.TopDocs;
36
import org.apache.lucene.search.WildcardQuery;
37
import org.apache.lucene.search.regex.RegexQuery;
38
import org.apache.lucene.util.Version;
39
import org.hibernate.criterion.Criterion;
40
import org.springframework.beans.factory.annotation.Autowired;
41
import org.springframework.beans.factory.annotation.Qualifier;
42
import org.springframework.stereotype.Service;
43
import org.springframework.transaction.annotation.Transactional;
44

    
45
import eu.etaxonomy.cdm.api.service.config.NameDeletionConfigurator;
46
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
47
import eu.etaxonomy.cdm.api.service.pager.Pager;
48
import eu.etaxonomy.cdm.api.service.pager.impl.AbstractPagerImpl;
49
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
50
import eu.etaxonomy.cdm.api.service.search.DocumentSearchResult;
51
import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
52
import eu.etaxonomy.cdm.api.service.search.LuceneSearch;
53
import eu.etaxonomy.cdm.api.service.search.QueryFactory;
54
import eu.etaxonomy.cdm.api.service.search.SearchResult;
55
import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;
56
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
57
import eu.etaxonomy.cdm.model.CdmBaseType;
58
import eu.etaxonomy.cdm.model.common.CdmBase;
59
import eu.etaxonomy.cdm.model.common.DescriptionElementSource;
60
import eu.etaxonomy.cdm.model.common.Language;
61
import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
62
import eu.etaxonomy.cdm.model.common.ReferencedEntityBase;
63
import eu.etaxonomy.cdm.model.common.RelationshipBase;
64
import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
65
import eu.etaxonomy.cdm.model.common.TermVocabulary;
66
import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;
67
import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
68
import eu.etaxonomy.cdm.model.name.HybridRelationship;
69
import eu.etaxonomy.cdm.model.name.HybridRelationshipType;
70
import eu.etaxonomy.cdm.model.name.NameRelationship;
71
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
72
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
73
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
74
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
75
import eu.etaxonomy.cdm.model.name.NonViralName;
76
import eu.etaxonomy.cdm.model.name.Rank;
77
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
78
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
79
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
80
import eu.etaxonomy.cdm.model.occurrence.DerivedUnitBase;
81
import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
82
import eu.etaxonomy.cdm.persistence.dao.common.IOrderedTermVocabularyDao;
83
import eu.etaxonomy.cdm.persistence.dao.common.IReferencedEntityDao;
84
import eu.etaxonomy.cdm.persistence.dao.common.ITermVocabularyDao;
85
import eu.etaxonomy.cdm.persistence.dao.name.IHomotypicalGroupDao;
86
import eu.etaxonomy.cdm.persistence.dao.name.INomenclaturalStatusDao;
87
import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
88
import eu.etaxonomy.cdm.persistence.dao.name.ITypeDesignationDao;
89
import eu.etaxonomy.cdm.persistence.query.MatchMode;
90
import eu.etaxonomy.cdm.persistence.query.OrderHint;
91
import eu.etaxonomy.cdm.strategy.cache.TaggedText;
92
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
93
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
94

    
95

    
96
@Service
97
@Transactional(readOnly = true)
98
public class NameServiceImpl extends IdentifiableServiceBase<TaxonNameBase,ITaxonNameDao> implements INameService {
99
    static private final Logger logger = Logger.getLogger(NameServiceImpl.class);
100

    
101
    @Autowired
102
    protected ITermVocabularyDao vocabularyDao;
103
    @Autowired
104
    protected IOrderedTermVocabularyDao orderedVocabularyDao;
105
    @Autowired
106
    @Qualifier("refEntDao")
107
    protected IReferencedEntityDao<ReferencedEntityBase> referencedEntityDao;
108
    @Autowired
109
    private INomenclaturalStatusDao nomStatusDao;
110
    @Autowired
111
    private ITypeDesignationDao typeDesignationDao;
112
    @Autowired
113
    private IHomotypicalGroupDao homotypicalGroupDao;
114
    @Autowired
115
    private ICdmGenericDao genericDao;
116

    
117
    /**
118
     * Constructor
119
     */
120
    public NameServiceImpl(){
121
        if (logger.isDebugEnabled()) { logger.debug("Load NameService Bean"); }
122
    }
123

    
124
//********************* METHODS ****************************************************************//
125

    
126
    /* (non-Javadoc)
127
     * @see eu.etaxonomy.cdm.api.service.ServiceBase#delete(eu.etaxonomy.cdm.model.common.CdmBase)
128
     */
129
    @Override
130
    public UUID delete(TaxonNameBase name){
131
        NameDeletionConfigurator config = new NameDeletionConfigurator();
132
        try {
133
            return delete(name, config);
134
        } catch (ReferencedObjectUndeletableException e) {
135
            //TODO throw DeleteException - current implementation is preliminary for testing
136
            throw new RuntimeException(e);
137
        }
138
    }
139

    
140
    /* (non-Javadoc)
141
     * @see eu.etaxonomy.cdm.api.service.INameService#delete(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.api.service.NameDeletionConfigurator)
142
     */
143
    @Override
144
    public UUID delete(TaxonNameBase name, NameDeletionConfigurator config) throws ReferencedObjectUndeletableException{
145
        if (name == null){
146
            return null;
147
        }
148

    
149
        //remove references to this name
150
        removeNameRelationshipsByDeleteConfig(name, config);
151

    
152
        //check if this name is still used somewhere
153

    
154
        //name relationships
155
        if (! name.getNameRelations().isEmpty()){
156
            String message = "Name can't be deleted as it is used in name relationship(s). Remove name relationships prior to deletion.";
157
            throw new ReferencedObjectUndeletableException(message);
158
//			return null;
159
        }
160

    
161
        //concepts
162
        if (! name.getTaxonBases().isEmpty()){
163
            String message = "Name can't be deleted as it is used in concept(s). Remove or change concept prior to deletion.";
164
            throw new ReferencedObjectUndeletableException(message);
165
        }
166

    
167
        //hybrid relationships
168
        if (name.isInstanceOf(NonViralName.class)){
169
            NonViralName nvn = CdmBase.deproxy(name, NonViralName.class);
170
//			if (! nvn.getHybridChildRelations().isEmpty()){
171
//				String message = "Name can't be deleted as it is a child in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
172
//				throw new RuntimeException(message);
173
//			}
174
            if (! nvn.getHybridParentRelations().isEmpty()){
175
                String message = "Name can't be deleted as it is a parent in (a) hybrid relationship(s). Remove hybrid relationships prior to deletion.";
176
                throw new ReferencedObjectUndeletableException(message);
177
            }
178
        }
179

    
180
        //all type designation relationships are removed as they belong to the name
181
        deleteTypeDesignation(name, null);
182
//		//type designations
183
//		if (! name.getTypeDesignations().isEmpty()){
184
//			String message = "Name can't be deleted as it has types. Remove types prior to deletion.";
185
//			throw new ReferrencedObjectUndeletableException(message);
186
//		}
187

    
188
        //check references with only reverse mapping
189
        Set<CdmBase> referencingObjects = genericDao.getReferencingObjects(name);
190
        for (CdmBase referencingObject : referencingObjects){
191
            //DerivedUnitBase?.storedUnder
192
            if (referencingObject.isInstanceOf(DerivedUnitBase.class)){
193
                String message = "Name can't be deleted as it is used as derivedUnit#storedUnder by %s. Remove 'stored under' prior to deleting this name";
194
                message = String.format(message, CdmBase.deproxy(referencingObject, DerivedUnitBase.class).getTitleCache());
195
                throw new ReferencedObjectUndeletableException(message);
196
            }
197
            //DescriptionElementSource#nameUsedInSource
198
            if (referencingObject.isInstanceOf(DescriptionElementSource.class)){
199
                String message = "Name can't be deleted as it is used as descriptionElementSource#nameUsedInSource";
200
                throw new ReferencedObjectUndeletableException(message);
201
            }
202
            //NameTypeDesignation#typeName
203
            if (referencingObject.isInstanceOf(NameTypeDesignation.class)){
204
                String message = "Name can't be deleted as it is used as a name type in a NameTypeDesignation";
205
                throw new ReferencedObjectUndeletableException(message);
206
            }
207

    
208
            //TaxonNameDescriptions#taxonName
209
            //deleted via cascade?
210

    
211
            //NomenclaturalStatus
212
            //deleted via cascade?
213

    
214
        }
215

    
216
        //TODO inline references
217

    
218
        dao.delete(name);
219
        return name.getUuid();
220
    }
221

    
222
    /* (non-Javadoc)
223
     * @see eu.etaxonomy.cdm.api.service.INameService#deleteTypeDesignation(eu.etaxonomy.cdm.model.name.TaxonNameBase, eu.etaxonomy.cdm.model.name.TypeDesignationBase)
224
     */
225
    @Override
226
    public void deleteTypeDesignation(TaxonNameBase name, TypeDesignationBase typeDesignation){
227
        if (name == null && typeDesignation == null){
228
            return;
229
        }else if (name != null && typeDesignation != null){
230
            removeSingleDesignation(name, typeDesignation);
231
        }else if (name != null){
232
            Set<TypeDesignationBase> designationSet = new HashSet<TypeDesignationBase>(name.getTypeDesignations());
233
            for (Object o : designationSet){
234
                TypeDesignationBase desig = CdmBase.deproxy(o, TypeDesignationBase.class);
235
                removeSingleDesignation(name, desig);
236
            }
237
        }else if (typeDesignation != null){
238
            Set<TaxonNameBase> nameSet = new HashSet<TaxonNameBase>(typeDesignation.getTypifiedNames());
239
            for (Object o : nameSet){
240
                TaxonNameBase singleName = CdmBase.deproxy(o, TaxonNameBase.class);
241
                removeSingleDesignation(singleName, typeDesignation);
242
            }
243
        }
244
    }
245

    
246
    /**
247
     * @param name
248
     * @param typeDesignation
249
     */
250
    private void removeSingleDesignation(TaxonNameBase name, TypeDesignationBase typeDesignation) {
251
        name.removeTypeDesignation(typeDesignation);
252
        if (typeDesignation.getTypifiedNames().isEmpty()){
253
            typeDesignation.removeType();
254
            typeDesignationDao.delete(typeDesignation);
255
        }
256
    }
257

    
258

    
259

    
260
    /**
261
     * @param name
262
     * @param config
263
     */
264
    private void removeNameRelationshipsByDeleteConfig(TaxonNameBase name, NameDeletionConfigurator config) {
265
        if (config.isRemoveAllNameRelationships()){
266
            Set<NameRelationship> rels = name.getNameRelations();
267
            for (NameRelationship rel : rels){
268
                name.removeNameRelationship(rel);
269
            }
270
        }else{
271
            //relations to this name
272
            Set<NameRelationship> rels = name.getRelationsToThisName();
273
            for (NameRelationship rel : rels){
274
                if (config.isIgnoreHasBasionym() && NameRelationshipType.BASIONYM().equals(rel.getType() )){
275
                        name.removeNameRelationship(rel);
276
                }else if (config.isIgnoreHasReplacedSynonym() && NameRelationshipType.REPLACED_SYNONYM().equals(rel.getType())){
277
                    name.removeNameRelationship(rel);
278
                }
279
            }
280
            //relations from this name
281
            rels = name.getRelationsFromThisName();
282
            for (NameRelationship rel : rels){
283
                if (config.isIgnoreIsBasionymFor() && NameRelationshipType.BASIONYM().equals(rel.getType())  ){
284
                    name.removeNameRelationship(rel);
285
                }else if (config.isIgnoreIsReplacedSynonymFor() && NameRelationshipType.REPLACED_SYNONYM().equals(rel.getType())){
286
                    name.removeNameRelationship(rel);
287
                }
288
            }
289

    
290
        }
291
    }
292

    
293
//********************* METHODS ****************************************************************//
294

    
295
    /**
296
     * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
297
     * duplicate of findByName
298
     */
299
    @Override
300
    @Deprecated
301
    public List getNamesByName(String name){
302
        return super.findCdmObjectsByTitle(name);
303
    }
304

    
305
    /**
306
     * TODO candidate for harmonization
307
     * new name findByName
308
     */
309
    @Override
310
    public List<NonViralName> getNamesByNameCache(String nameCache){
311
        List result = dao.findByName(nameCache, MatchMode.EXACT, null, null, null, null);
312
        return result;
313
    }
314

    
315

    
316
    /**
317
     * TODO candidate for harmonization
318
     * new name saveHomotypicalGroups
319
     *
320
     * findByTitle
321
     */
322
    @Override
323
    public List<NonViralName> findNamesByTitleCache(String titleCache, MatchMode matchMode, List<String> propertyPaths){
324
        List result = dao.findByTitle(titleCache, matchMode, null, null, null ,propertyPaths);
325
        return result;
326
    }
327

    
328
    /**
329
     * TODO candidate for harmonization
330
     * new name saveHomotypicalGroups
331
     *
332
     * findByTitle
333
     */
334
    @Override
335
    public List<NonViralName> findNamesByNameCache(String nameCache, MatchMode matchMode, List<String> propertyPaths){
336
        List result = dao.findByName(nameCache, matchMode, null, null, null ,propertyPaths);
337
        return result;
338
    }
339

    
340
    /**
341
     * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
342
     * Replace by load(UUID, propertyPaths)
343
     */
344
    @Override
345
    @Deprecated
346
    public NonViralName findNameByUuid(UUID uuid, List<String> propertyPaths){
347
        return (NonViralName)dao.findByUuid(uuid, null ,propertyPaths);
348
    }
349

    
350
    /**
351
     * TODO candidate for harmonization
352
     */
353
    @Override
354
    public List getNamesByName(String name, CdmBase sessionObject){
355
        return super.findCdmObjectsByTitle(name, sessionObject);
356
    }
357

    
358
    /**
359
     * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
360
     * duplicate of findByTitle(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths)
361
     */
362
    @Override
363
    @Deprecated
364
    public List findNamesByTitle(String title){
365
        return super.findCdmObjectsByTitle(title);
366
    }
367

    
368
    /**
369
     * @deprecated To be removed for harmonization see http://dev.e-taxonomy.eu/trac/wiki/CdmLibraryConventions
370
     * duplicate of findByTitle()
371
     */
372
    @Override
373
    @Deprecated
374
    public List findNamesByTitle(String title, CdmBase sessionObject){
375
        return super.findCdmObjectsByTitle(title, sessionObject);
376
    }
377

    
378
    /**
379
     * TODO candidate for harmonization
380
     * new name saveHomotypicalGroups
381
     */
382
    @Override
383
    @Transactional(readOnly = false)
384
    public Map<UUID, HomotypicalGroup> saveAllHomotypicalGroups(Collection<HomotypicalGroup> homotypicalGroups){
385
        return homotypicalGroupDao.saveAll(homotypicalGroups);
386
    }
387

    
388
    /**
389
     * TODO candidate for harmonization
390
     * new name saveTypeDesignations
391
     */
392
    @Override
393
    @Transactional(readOnly = false)
394
    public Map<UUID, TypeDesignationBase> saveTypeDesignationAll(Collection<TypeDesignationBase> typeDesignationCollection){
395
        return typeDesignationDao.saveAll(typeDesignationCollection);
396
    }
397

    
398
    /**
399
     * TODO candidate for harmonization
400
     * new name saveReferencedEntities
401
     */
402
    @Override
403
    @Transactional(readOnly = false)
404
    public Map<UUID, ReferencedEntityBase> saveReferencedEntitiesAll(Collection<ReferencedEntityBase> referencedEntityCollection){
405
        return referencedEntityDao.saveAll(referencedEntityCollection);
406
    }
407

    
408
    /**
409
     * TODO candidate for harmonization
410
     * new name getNames
411
     */
412
    public List<TaxonNameBase> getAllNames(int limit, int start){
413
        return dao.list(limit, start);
414
    }
415

    
416
    /**
417
     * TODO candidate for harmonization
418
     * new name getNomenclaturalStatus
419
     */
420
    @Override
421
    public List<NomenclaturalStatus> getAllNomenclaturalStatus(int limit, int start){
422
        return nomStatusDao.list(limit, start);
423
    }
424

    
425
    /**
426
     * TODO candidate for harmonization
427
     * new name getTypeDesignations
428
     */
429
    @Override
430
    public List<TypeDesignationBase> getAllTypeDesignations(int limit, int start){
431
        return typeDesignationDao.getAllTypeDesignations(limit, start);
432
    }
433
      /**
434
     * FIXME Candidate for harmonization
435
     * homotypicalGroupService.list
436
     */
437
    @Override
438
    public List<HomotypicalGroup> getAllHomotypicalGroups(int limit, int start){
439
        return homotypicalGroupDao.list(limit, start);
440
    }
441

    
442
    /**
443
     * FIXME Candidate for harmonization
444
     * remove
445
     */
446
    @Override
447
    @Deprecated
448
    public List<RelationshipBase> getAllRelationships(int limit, int start){
449
        return dao.getAllRelationships(limit, start);
450
    }
451

    
452
    /**
453
     * FIXME Candidate for harmonization
454
     * is this not the same as termService.getVocabulary(VocabularyEnum.Rank)
455
     * since this returns OrderedTermVocabulary
456
     *
457
     * (non-Javadoc)
458
     * @see eu.etaxonomy.cdm.api.service.INameService#getRankVocabulary()
459
     */
460
    @Override
461
    public OrderedTermVocabulary<Rank> getRankVocabulary() {
462
        String uuidString = "ef0d1ce1-26e3-4e83-b47b-ca74eed40b1b";
463
        UUID uuid = UUID.fromString(uuidString);
464
        OrderedTermVocabulary<Rank> rankVocabulary =
465
            (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
466
        return rankVocabulary;
467
    }
468

    
469
    /**
470
      * FIXME Candidate for harmonization
471
     * is this the same as termService.getVocabulary(VocabularyEnum.NameRelationshipType)
472
     *  (non-Javadoc)
473
     * @see eu.etaxonomy.cdm.api.service.INameService#getNameRelationshipTypeVocabulary()
474
     */
475
    @Override
476
    public TermVocabulary<NameRelationshipType> getNameRelationshipTypeVocabulary() {
477
        String uuidString = "6878cb82-c1a4-4613-b012-7e73b413c8cd";
478
        UUID uuid = UUID.fromString(uuidString);
479
        TermVocabulary<NameRelationshipType> nameRelTypeVocabulary =
480
            vocabularyDao.findByUuid(uuid);
481
        return nameRelTypeVocabulary;
482
    }
483

    
484
    /**
485
      * FIXME Candidate for harmonization
486
     * is this the same as termService.getVocabulary(VocabularyEnum.StatusType)
487
     * (non-Javadoc)
488
     * @see eu.etaxonomy.cdm.api.service.INameService#getStatusTypeVocabulary()
489
     */
490
    @Override
491
    public TermVocabulary<NomenclaturalStatusType> getStatusTypeVocabulary() {
492
        String uuidString = "bb28cdca-2f8a-4f11-9c21-517e9ae87f1f";
493
        UUID uuid = UUID.fromString(uuidString);
494
        TermVocabulary<NomenclaturalStatusType> nomStatusTypeVocabulary =
495
            vocabularyDao.findByUuid(uuid);
496
        return nomStatusTypeVocabulary;
497
    }
498

    
499
    /**
500
      * FIXME Candidate for harmonization
501
     * is this the same as termService.getVocabulary(VocabularyEnum.SpecimenTypeDesignationStatus)
502
     *  (non-Javadoc)
503
     * @see eu.etaxonomy.cdm.api.service.INameService#getTypeDesignationStatusVocabulary()
504
     */
505
    @Override
506
    public TermVocabulary<SpecimenTypeDesignationStatus> getSpecimenTypeDesignationStatusVocabulary() {
507
        String uuidString = "ab177bd7-d3c8-4e58-a388-226fff6ba3c2";
508
        UUID uuid = UUID.fromString(uuidString);
509
        TermVocabulary<SpecimenTypeDesignationStatus> typeDesigStatusVocabulary =
510
            vocabularyDao.findByUuid(uuid);
511
        return typeDesigStatusVocabulary;
512
    }
513

    
514
    /**
515
       * FIXME Candidate for harmonization
516
     * is this the same as termService.getVocabulary(VocabularyEnum.SpecimenTypeDesignationStatus)
517
     * and also seems to duplicate the above method, differing only in the DAO used and the return type
518
     * (non-Javadoc)
519
     * @see eu.etaxonomy.cdm.api.service.INameService#getTypeDesignationStatusVocabulary()
520
     */
521
    @Override
522
    public OrderedTermVocabulary<SpecimenTypeDesignationStatus> getSpecimenTypeDesignationVocabulary() {
523
        String uuidString = "ab177bd7-d3c8-4e58-a388-226fff6ba3c2";
524
        UUID uuid = UUID.fromString(uuidString);
525
        OrderedTermVocabulary<SpecimenTypeDesignationStatus> typeDesignationVocabulary =
526
            (OrderedTermVocabulary)orderedVocabularyDao.findByUuid(uuid);
527
        return typeDesignationVocabulary;
528
    }
529

    
530

    
531
    @Override
532
    @Autowired
533
    protected void setDao(ITaxonNameDao dao) {
534
        this.dao = dao;
535
    }
536

    
537
    @Override
538
    public Pager<HybridRelationship> getHybridNames(NonViralName name,	HybridRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
539
        Integer numberOfResults = dao.countHybridNames(name, type);
540

    
541
        List<HybridRelationship> results = new ArrayList<HybridRelationship>();
542
        if(AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)) { // no point checking again
543
            results = dao.getHybridNames(name, type, pageSize, pageNumber,orderHints,propertyPaths);
544
        }
545

    
546
        return new DefaultPagerImpl<HybridRelationship>(pageNumber, numberOfResults, pageSize, results);
547
    }
548

    
549
    /* (non-Javadoc)
550
     * @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)
551
     */
552
    @Override
553
    public List<NameRelationship> listNameRelationships(TaxonNameBase name,	Direction direction, NameRelationshipType type, Integer pageSize,
554
            Integer pageNumber, List<OrderHint> orderHints,	List<String> propertyPaths) {
555

    
556
        Integer numberOfResults = dao.countNameRelationships(name, NameRelationship.Direction.relatedFrom, type);
557

    
558
        List<NameRelationship> results = new ArrayList<NameRelationship>();
559
        if (AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)) { // no point checking again
560
            results = dao.getNameRelationships(name, direction, type, pageSize,	pageNumber, orderHints, propertyPaths);
561
        }
562
        return results;
563
    }
564

    
565

    
566
    protected LuceneSearch prepareFindByFuzzyNameSearch(Class<? extends CdmBase> clazz, 
567
    		NonViralName nvn,
568
    		float accuracy,
569
    		List<Language> languages,
570
    		boolean highlightFragments) {
571
    	String similarity = Float.toString(accuracy);    	
572
    	String searchSuffix = "~" + similarity;
573
    	
574

    
575
    	BooleanQuery finalQuery = new BooleanQuery();
576
    	BooleanQuery textQuery = new BooleanQuery();
577

    
578
    	LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonNameBase.class);    	   
579
    	QueryFactory queryFactory = new QueryFactory(luceneSearch);
580

    
581
    	SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};
582
    	luceneSearch.setSortFields(sortFields);
583

    
584
    	// ---- search criteria
585
    	luceneSearch.setClazz(clazz);
586

    
587
    	
588
    	if(nvn.getGenusOrUninomial() != null && !nvn.getGenusOrUninomial().equals("")) {        	
589
    		textQuery.add(queryFactory.newTermQuery("genusOrUninomial", nvn.getGenusOrUninomial() + searchSuffix), Occur.SHOULD);
590
    		
591
    	} else {
592
    		textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);
593
    	}
594

    
595
    	if(nvn.getInfraGenericEpithet() != null && !nvn.getInfraGenericEpithet().equals("")){
596
    		textQuery.add(queryFactory.newTermQuery("infraGenericEpithet", nvn.getInfraGenericEpithet() + searchSuffix), Occur.SHOULD);
597
    	} else {
598
    		textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
599
    	}
600

    
601
    	if(nvn.getSpecificEpithet() != null && !nvn.getSpecificEpithet().equals("")){
602
    		textQuery.add(queryFactory.newTermQuery("specificEpithet", nvn.getSpecificEpithet() + searchSuffix), Occur.SHOULD);  
603

    
604
    	} else {
605
    		textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
606
    	}
607

    
608
    	if(nvn.getInfraSpecificEpithet() != null && !nvn.getInfraSpecificEpithet().equals("")){
609
    		textQuery.add(queryFactory.newTermQuery("infraSpecificEpithet", nvn.getInfraSpecificEpithet() + searchSuffix), Occur.SHOULD);
610
    	} else {
611
    		textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
612
    	}
613

    
614
    	if(nvn.getAuthorshipCache() != null && !nvn.getAuthorshipCache().equals("")){
615
    		textQuery.add(queryFactory.newTermQuery("authorshipCache", nvn.getAuthorshipCache() + searchSuffix), Occur.SHOULD);
616
    	} else {
617
    		//textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);
618
    	}
619

    
620
    	finalQuery.add(textQuery, Occur.MUST);
621

    
622
    	luceneSearch.setQuery(finalQuery);
623

    
624
    	if(highlightFragments){
625
    		luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
626
    	}
627
    	return luceneSearch;
628
    }
629
    
630
    protected LuceneSearch prepareFindByExactNameSearch(Class<? extends CdmBase> clazz, 
631
    		String name,
632
    		boolean wildcard,
633
    		List<Language> languages,
634
            boolean highlightFragments) {
635
        BooleanQuery finalQuery = new BooleanQuery();
636
        BooleanQuery textQuery = new BooleanQuery();
637

    
638
        LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonNameBase.class);
639
        QueryFactory queryFactory = new QueryFactory(luceneSearch);
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.setClazz(clazz);
646
        
647
        
648
        
649
        if(name != null && !name.equals("")) {        	        	
650
        	if(wildcard) {
651
        		textQuery.add(new WildcardQuery(new Term("nameCache", name + "*")), Occur.MUST);
652
        	} else {
653
        		textQuery.add(queryFactory.newTermQuery("nameCache", name, false), Occur.MUST);
654
        	}
655
        } 
656
        
657
        finalQuery.add(textQuery, Occur.MUST);
658

    
659
        luceneSearch.setQuery(textQuery);
660

    
661
        if(highlightFragments){
662
            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
663
        }
664
        return luceneSearch;
665
    }
666
    
667
    public List<SearchResult<TaxonNameBase>> findByNameFuzzySearch(
668
            String name,
669
            float accuracy,
670
            List<Language> languages,
671
            boolean highlightFragments, 
672
            List<String> propertyPaths,
673
            int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
674

    
675
    	logger.info("Name to fuzzy search for : " + name);
676
    	// parse the input name
677
    	NonViralNameParserImpl parser = new NonViralNameParserImpl();
678
    	NonViralName nvn = parser.parseFullName(name);
679
    	if(name != null && !name.equals("") && nvn == null) {
680
    		throw new ParseException("Could not parse name " + name);
681
    	}
682
        LuceneSearch luceneSearch = prepareFindByFuzzyNameSearch(null, nvn, accuracy, languages, highlightFragments);
683

    
684
        // --- execute search        
685
        TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
686

    
687
        
688
        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
689
        idFieldMap.put(CdmBaseType.NONVIRALNAME, "id");
690

    
691
        // --- initialize taxa, highlight matches ....
692
        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
693
        
694
        @SuppressWarnings("rawtypes")
695
        List<SearchResult<TaxonNameBase>> searchResults = searchResultBuilder.createResultSet(
696
                topDocs, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
697

    
698
        return searchResults;
699

    
700
    }
701
    
702
    public List<DocumentSearchResult> findByNameFuzzySearch(
703
            String name,
704
            float accuracy,
705
            List<Language> languages,
706
            boolean highlightFragments, 
707
            int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
708

    
709
    	logger.info("Name to fuzzy search for : " + name);
710
    	// parse the input name
711
    	NonViralNameParserImpl parser = new NonViralNameParserImpl();
712
    	NonViralName nvn = parser.parseFullName(name);
713
    	if(name != null && !name.equals("") && nvn == null) {
714
    		throw new ParseException("Could not parse name " + name);
715
    	}
716
        LuceneSearch luceneSearch = prepareFindByFuzzyNameSearch(null, nvn, accuracy, languages, highlightFragments);
717

    
718
        // --- execute search        
719
        TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
720
//        for(int i = 0; i < topDocs.scoreDocs.length ; i++) {
721
//        	Explanation exp = luceneSearch.getSearcher().explain(luceneSearch.getQuery(), topDocs.scoreDocs[i].doc);
722
//        	System.out.println("-----------------------");
723
//        	System.out.println(exp.toString());
724
//        }
725
        
726
        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
727

    
728
        // --- initialize taxa, highlight matches ....
729
        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
730
        
731
        @SuppressWarnings("rawtypes")
732
        List<DocumentSearchResult> searchResults = searchResultBuilder.createResultSet(topDocs, luceneSearch.getHighlightFields());
733

    
734
        return searchResults;
735
    }
736
    
737
    public List<DocumentSearchResult> findByNameExactSearch(
738
            String name,
739
            boolean wildcard,
740
            List<Language> languages,
741
            boolean highlightFragments, 
742
            int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
743

    
744
    	logger.info("Name to fuzzy search for : " + name);
745
    	
746
        LuceneSearch luceneSearch = prepareFindByExactNameSearch(null, name, wildcard, languages, highlightFragments);
747

    
748
        // --- execute search        
749
        TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
750
        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();        
751

    
752
        // --- initialize taxa, highlight matches ....
753
        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
754
        
755
        @SuppressWarnings("rawtypes")
756
        List<DocumentSearchResult> searchResults = searchResultBuilder.createResultSet(topDocs, luceneSearch.getHighlightFields());
757

    
758
        return searchResults;
759
    }
760
    
761
    /* (non-Javadoc)
762
     * @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)
763
     */
764
    @Override
765
    public Pager<NameRelationship> pageNameRelationships(TaxonNameBase name, Direction direction, NameRelationshipType type, Integer pageSize,
766
            Integer pageNumber, List<OrderHint> orderHints,	List<String> propertyPaths) {
767
        List<NameRelationship> results = listNameRelationships(name, direction, type, pageSize, pageNumber, orderHints, propertyPaths);
768
        return new DefaultPagerImpl<NameRelationship>(pageNumber, results.size(), pageSize, results);
769
    }
770

    
771
    @Override
772
    public List<NameRelationship> listFromNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
773
        return listNameRelationships(name, Direction.relatedFrom, type, pageSize, pageNumber, orderHints, propertyPaths);
774
    }
775

    
776
    @Override
777
    public Pager<NameRelationship> pageFromNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
778
        List<NameRelationship> results = listNameRelationships(name, Direction.relatedFrom, type, pageSize, pageNumber, orderHints, propertyPaths);
779
        return new DefaultPagerImpl<NameRelationship>(pageNumber, results.size(), pageSize, results);
780
    }
781

    
782
    @Override
783
    public List<NameRelationship> listToNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
784
        return listNameRelationships(name, Direction.relatedTo, type, pageSize, pageNumber, orderHints, propertyPaths);
785
    }
786

    
787
    @Override
788
    public Pager<NameRelationship> pageToNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
789
        List<NameRelationship> results = listNameRelationships(name, Direction.relatedTo, type, pageSize, pageNumber, orderHints, propertyPaths);
790
        return new DefaultPagerImpl<NameRelationship>(pageNumber, results.size(), pageSize, results);
791
    }
792

    
793
    @Override
794
    public Pager<TypeDesignationBase> getTypeDesignations(TaxonNameBase name, SpecimenTypeDesignationStatus status,
795
            Integer pageSize, Integer pageNumber) {
796
        return getTypeDesignations(name, status, pageSize, pageNumber, null);
797
    }
798

    
799
    @Override
800
    public Pager<TypeDesignationBase> getTypeDesignations(TaxonNameBase name, SpecimenTypeDesignationStatus status,
801
                Integer pageSize, Integer pageNumber, List<String> propertyPaths){
802
        Integer numberOfResults = dao.countTypeDesignations(name, status);
803

    
804
        List<TypeDesignationBase> results = new ArrayList<TypeDesignationBase>();
805
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
806
            results = dao.getTypeDesignations(name, status, pageSize, pageNumber, propertyPaths);
807
        }
808

    
809
        return new DefaultPagerImpl<TypeDesignationBase>(pageNumber, numberOfResults, pageSize, results);
810
    }
811

    
812
    /**
813
     * FIXME Candidate for harmonization
814
     * rename search
815
     */
816
    @Override
817
    public Pager<TaxonNameBase> searchNames(String uninomial,String infraGenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,	Integer pageNumber, List<OrderHint> orderHints,
818
            List<String> propertyPaths) {
819
        Integer numberOfResults = dao.countNames(uninomial, infraGenericEpithet, specificEpithet, infraspecificEpithet, rank);
820

    
821
        List<TaxonNameBase> results = new ArrayList<TaxonNameBase>();
822
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
823
            results = dao.searchNames(uninomial, infraGenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber, orderHints, propertyPaths);
824
        }
825

    
826
        return new DefaultPagerImpl<TaxonNameBase>(pageNumber, numberOfResults, pageSize, results);
827
    }
828

    
829
    /* (non-Javadoc)
830
     * @see eu.etaxonomy.cdm.api.service.INameService#getUuidAndTitleCacheOfNames()
831
     */
832
    @Override
833
    public List<UuidAndTitleCache> getUuidAndTitleCacheOfNames() {
834
        return dao.getUuidAndTitleCacheOfNames();
835
    }
836

    
837
    @Override
838
    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) {
839
        Integer numberOfResults = dao.countByName(clazz, queryString, matchmode, criteria);
840

    
841
         List<TaxonNameBase> results = new ArrayList<TaxonNameBase>();
842
         if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
843
                results = dao.findByName(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);
844
         }
845

    
846
          return new DefaultPagerImpl<TaxonNameBase>(pageNumber, numberOfResults, pageSize, results);
847
    }
848

    
849
    @Override
850
    public HomotypicalGroup findHomotypicalGroup(UUID uuid) {
851
        return homotypicalGroupDao.findByUuid(uuid);
852
    }
853

    
854

    
855
    /* (non-Javadoc)
856
     * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
857
     */
858
    @Override
859
    @Transactional(readOnly = false)
860
    public void updateTitleCache(Class<? extends TaxonNameBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<TaxonNameBase> cacheStrategy, IProgressMonitor monitor) {
861
        if (clazz == null){
862
            clazz = TaxonNameBase.class;
863
        }
864
        super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
865
    }
866

    
867

    
868
    @Override
869
    protected void setOtherCachesNull(TaxonNameBase name) {
870
        if (name.isInstanceOf(NonViralName.class)){
871
            NonViralName<?> nvn = CdmBase.deproxy(name, NonViralName.class);
872
            if (! nvn.isProtectedNameCache()){
873
                nvn.setNameCache(null, false);
874
            }
875
            if (! nvn.isProtectedAuthorshipCache()){
876
                nvn.setAuthorshipCache(null, false);
877
            }
878
            if (! nvn.isProtectedFullTitleCache()){
879
                nvn.setFullTitleCache(null, false);
880
            }
881
        }
882
    }
883

    
884
    /* (non-Javadoc)
885
     * @see eu.etaxonomy.cdm.api.service.INameService#getTaggedName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
886
     */
887
    @Override
888
    public List<TaggedText> getTaggedName(UUID uuid) {
889
        TaxonNameBase taxonNameBase = dao.load(uuid);
890
        List taggedName = taxonNameBase.getTaggedName();
891
        return taggedName;
892
    }
893

    
894

    
895
}
(66-66/81)