Project

General

Profile

Download (41.1 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.FuzzyQuery;
32
import org.apache.lucene.search.PhraseQuery;
33
import org.apache.lucene.search.Query;
34
import org.apache.lucene.search.SortField;
35
import org.apache.lucene.search.BooleanClause.Occur;
36
import org.apache.lucene.search.TermQuery;
37
import org.apache.lucene.search.TopDocs;
38
import org.apache.lucene.search.WildcardQuery;
39
import org.apache.lucene.search.regex.RegexQuery;
40
import org.apache.lucene.util.Version;
41
import org.hibernate.criterion.Criterion;
42
import org.springframework.beans.factory.annotation.Autowired;
43
import org.springframework.beans.factory.annotation.Qualifier;
44
import org.springframework.stereotype.Service;
45
import org.springframework.transaction.annotation.Transactional;
46

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

    
97

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

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

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

    
126
//********************* METHODS ****************************************************************//
127

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

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

    
151
        //remove references to this name
152
        removeNameRelationshipsByDeleteConfig(name, config);
153

    
154
        //check if this name is still used somewhere
155

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

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

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

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

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

    
210
            //TaxonNameDescriptions#taxonName
211
            //deleted via cascade?
212

    
213
            //NomenclaturalStatus
214
            //deleted via cascade?
215

    
216
        }
217

    
218
        //TODO inline references
219

    
220
        dao.delete(name);
221
        return name.getUuid();
222
    }
223

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

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

    
260

    
261

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

    
292
        }
293
    }
294

    
295
//********************* METHODS ****************************************************************//
296

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

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

    
317

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
532

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

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

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

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

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

    
558
        Integer numberOfResults = dao.countNameRelationships(name, NameRelationship.Direction.relatedFrom, type);
559

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

    
567

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

    
578
    	BooleanQuery finalQuery = new BooleanQuery(false);
579
    	BooleanQuery textQuery = new BooleanQuery(false);
580

    
581
    	LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonNameBase.class);    	   
582
        QueryFactory queryFactory = new QueryFactory(luceneSearch);
583
    	
584
//    	SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};
585
//    	luceneSearch.setSortFields(sortFields);
586

    
587
        // ---- search criteria
588
        luceneSearch.setClazz(clazz);
589
    	
590
    	FuzzyLikeThisQuery fltq = new FuzzyLikeThisQuery(maxNoOfResults, luceneSearch.getAnalyzer());
591
        if(nvn.getGenusOrUninomial() != null && !nvn.getGenusOrUninomial().equals("")) {        	
592
    		fltq.addTerms(nvn.getGenusOrUninomial().toLowerCase(), "genusOrUninomial", accuracy, 3);    		
593
        } else {
594
    		//textQuery.add(new RegexQuery (new Term ("genusOrUninomial", "^[a-zA-Z]*")), Occur.MUST_NOT);
595
    		textQuery.add(queryFactory.newTermQuery("genusOrUninomial", "_null_", false), Occur.MUST);
596
        }
597

    
598
        if(nvn.getInfraGenericEpithet() != null && !nvn.getInfraGenericEpithet().equals("")){
599
    		fltq.addTerms(nvn.getInfraGenericEpithet().toLowerCase(), "infraGenericEpithet", accuracy, 3); 
600
        } else {
601
    		//textQuery.add(new RegexQuery (new Term ("infraGenericEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
602
    		textQuery.add(queryFactory.newTermQuery("infraGenericEpithet", "_null_", false), Occur.MUST);
603
        }
604

    
605
        if(nvn.getSpecificEpithet() != null && !nvn.getSpecificEpithet().equals("")){
606
    		fltq.addTerms(nvn.getSpecificEpithet().toLowerCase(), "specificEpithet", accuracy, 3); 
607
        } else {
608
    		//textQuery.add(new RegexQuery (new Term ("specificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
609
    		textQuery.add(queryFactory.newTermQuery("specificEpithet", "_null_", false), Occur.MUST);
610
        }
611

    
612
        if(nvn.getInfraSpecificEpithet() != null && !nvn.getInfraSpecificEpithet().equals("")){
613
    		fltq.addTerms(nvn.getInfraSpecificEpithet().toLowerCase(), "infraSpecificEpithet", accuracy, 3); 
614
        } else {
615
    		//textQuery.add(new RegexQuery (new Term ("infraSpecificEpithet", "^[a-zA-Z]*")), Occur.MUST_NOT);
616
    		textQuery.add(queryFactory.newTermQuery("infraSpecificEpithet", "_null_", false), Occur.MUST);
617
        }
618

    
619
        if(nvn.getAuthorshipCache() != null && !nvn.getAuthorshipCache().equals("")){
620
    		fltq.addTerms(nvn.getAuthorshipCache().toLowerCase(), "authorshipCache", accuracy, 3);
621
        } else {
622
    		//textQuery.add(new RegexQuery (new Term ("authorshipCache", "^[a-zA-Z]*")), Occur.MUST_NOT);
623
        }
624

    
625
    	textQuery.add(fltq, Occur.MUST);    	    
626

    
627
    	finalQuery.add(textQuery, Occur.MUST); 
628
        
629
    	luceneSearch.setQuery(finalQuery);
630

    
631
    	if(highlightFragments){
632
    		luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
633
    	}
634
    	return luceneSearch;
635
    }
636
    
637
    protected LuceneSearch prepareFindByFuzzyNameCacheSearch(Class<? extends CdmBase> clazz, 
638
    		String name,
639
    		float accuracy,
640
    		int maxNoOfResults,    		
641
    		List<Language> languages,
642
            boolean highlightFragments) {    	    	
643

    
644
        LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonNameBase.class);
645
        QueryFactory queryFactory = new QueryFactory(luceneSearch);
646

    
647
//    	SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};
648
//    	luceneSearch.setSortFields(sortFields);
649
    	
650
        // ---- search criteria
651
        luceneSearch.setClazz(clazz);
652
        FuzzyLikeThisQuery fltq = new FuzzyLikeThisQuery(maxNoOfResults, luceneSearch.getAnalyzer());                      
653

    
654
        fltq.addTerms(name, "nameCache", accuracy, 3);           
655

    
656
     	BooleanQuery finalQuery = new BooleanQuery(false);
657
     	
658
     	finalQuery.add(fltq, Occur.MUST);   
659
     	
660
        luceneSearch.setQuery(finalQuery);
661

    
662
        if(highlightFragments){
663
            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
664
        }
665
        return luceneSearch;
666
    }
667
    
668
    protected LuceneSearch prepareFindByExactNameSearch(Class<? extends CdmBase> clazz, 
669
    		String name,
670
    		boolean wildcard,
671
    		List<Language> languages,
672
            boolean highlightFragments) {
673
        BooleanQuery finalQuery = new BooleanQuery();
674
        BooleanQuery textQuery = new BooleanQuery();
675

    
676
        LuceneSearch luceneSearch = new LuceneSearch(getSession(), TaxonNameBase.class);
677
        QueryFactory queryFactory = new QueryFactory(luceneSearch);
678

    
679
//    	SortField[] sortFields = new  SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING,  false)};
680
//    	luceneSearch.setSortFields(sortFields);
681

    
682
        // ---- search criteria
683
        luceneSearch.setClazz(clazz);
684
                             
685
        if(name != null && !name.equals("")) {        	        	
686
        	if(wildcard) {
687
        		textQuery.add(new WildcardQuery(new Term("nameCache", name + "*")), Occur.MUST);        		
688
        	} else {        		
689
        		textQuery.add(queryFactory.newTermQuery("nameCache", name, false), Occur.MUST);   		
690
        	}
691
        }                
692

    
693
        luceneSearch.setQuery(textQuery);
694

    
695
        if(highlightFragments){
696
            luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
697
        }
698
        return luceneSearch;
699
    }
700
    
701
    public List<SearchResult<TaxonNameBase>> findByNameFuzzySearch(
702
            String name,
703
            float accuracy,
704
            List<Language> languages,
705
            boolean highlightFragments, 
706
            List<String> propertyPaths,
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, maxNoOfResults, languages, highlightFragments);
717

    
718
        // --- execute search        
719
        TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
720

    
721
        
722
        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
723
        idFieldMap.put(CdmBaseType.NONVIRALNAME, "id");
724

    
725
        // --- initialize taxa, highlight matches ....
726
        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
727
        
728
        @SuppressWarnings("rawtypes")
729
        List<SearchResult<TaxonNameBase>> searchResults = searchResultBuilder.createResultSet(
730
                topDocs, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
731

    
732
        return searchResults;
733

    
734
    }
735
    
736
    public List<DocumentSearchResult> findByNameFuzzySearch(
737
            String name,
738
            float accuracy,
739
            List<Language> languages,
740
            boolean highlightFragments, 
741
            int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
742

    
743
    	logger.info("Name to fuzzy search for : " + name);
744
    	// parse the input name
745
    	NonViralNameParserImpl parser = new NonViralNameParserImpl();
746
    	NonViralName nvn = parser.parseFullName(name);
747
    	if(name != null && !name.equals("") && nvn == null) {
748
    		throw new ParseException("Could not parse name " + name);
749
    	}
750
        LuceneSearch luceneSearch = prepareFindByFuzzyNameSearch(null, nvn, accuracy, maxNoOfResults, languages, highlightFragments);
751

    
752
        // --- execute search        
753
        TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
754
        
755
        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
756

    
757
        // --- initialize taxa, highlight matches ....
758
        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
759
        
760
        @SuppressWarnings("rawtypes")
761
        List<DocumentSearchResult> searchResults = searchResultBuilder.createResultSet(topDocs, luceneSearch.getHighlightFields());
762

    
763
        return searchResults;
764
    }
765
    
766
    public List<DocumentSearchResult> findByFuzzyNameCacheSearch(
767
            String name,
768
    		float accuracy,            
769
            List<Language> languages,
770
            boolean highlightFragments,
771
            int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
772

    
773
    	logger.info("Name to fuzzy search for : " + name);
774
    	
775
        LuceneSearch luceneSearch = prepareFindByFuzzyNameCacheSearch(null, name, accuracy, maxNoOfResults, languages, highlightFragments);
776

    
777
        // --- execute search        
778
        TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
779
        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();        
780

    
781
        // --- initialize taxa, highlight matches ....
782
        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
783
        
784
        @SuppressWarnings("rawtypes")
785
        List<DocumentSearchResult> searchResults = searchResultBuilder.createResultSet(topDocs, luceneSearch.getHighlightFields());
786

    
787
        return searchResults;
788
    }
789
    
790
    public List<DocumentSearchResult> findByNameExactSearch(
791
            String name,
792
            boolean wildcard,
793
            List<Language> languages,
794
            boolean highlightFragments, 
795
            int maxNoOfResults) throws CorruptIndexException, IOException, ParseException {
796

    
797
    	logger.info("Name to exact search for : " + name);
798
    	
799
    	LuceneSearch luceneSearch = prepareFindByExactNameSearch(null, name, wildcard, languages, highlightFragments);
800

    
801
        // --- execute search        
802
    
803
        
804
        TopDocs topDocs = luceneSearch.executeSearch(maxNoOfResults);
805
        
806
        Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();        
807

    
808
        // --- initialize taxa, highlight matches ....
809
        ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
810
        
811
        @SuppressWarnings("rawtypes")
812
        List<DocumentSearchResult> searchResults = searchResultBuilder.createResultSet(topDocs, luceneSearch.getHighlightFields());
813

    
814
        return searchResults;
815
    }
816
    
817
    /* (non-Javadoc)
818
     * @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)
819
     */
820
    @Override
821
    public Pager<NameRelationship> pageNameRelationships(TaxonNameBase name, Direction direction, NameRelationshipType type, Integer pageSize,
822
            Integer pageNumber, List<OrderHint> orderHints,	List<String> propertyPaths) {
823
        List<NameRelationship> results = listNameRelationships(name, direction, type, pageSize, pageNumber, orderHints, propertyPaths);
824
        return new DefaultPagerImpl<NameRelationship>(pageNumber, results.size(), pageSize, results);
825
    }
826

    
827
    @Override
828
    public List<NameRelationship> listFromNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
829
        return listNameRelationships(name, Direction.relatedFrom, type, pageSize, pageNumber, orderHints, propertyPaths);
830
    }
831

    
832
    @Override
833
    public Pager<NameRelationship> pageFromNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
834
        List<NameRelationship> results = listNameRelationships(name, Direction.relatedFrom, type, pageSize, pageNumber, orderHints, propertyPaths);
835
        return new DefaultPagerImpl<NameRelationship>(pageNumber, results.size(), pageSize, results);
836
    }
837

    
838
    @Override
839
    public List<NameRelationship> listToNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
840
        return listNameRelationships(name, Direction.relatedTo, type, pageSize, pageNumber, orderHints, propertyPaths);
841
    }
842

    
843
    @Override
844
    public Pager<NameRelationship> pageToNameRelationships(TaxonNameBase name, NameRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
845
        List<NameRelationship> results = listNameRelationships(name, Direction.relatedTo, type, pageSize, pageNumber, orderHints, propertyPaths);
846
        return new DefaultPagerImpl<NameRelationship>(pageNumber, results.size(), pageSize, results);
847
    }
848

    
849
    @Override
850
    public Pager<TypeDesignationBase> getTypeDesignations(TaxonNameBase name, SpecimenTypeDesignationStatus status,
851
            Integer pageSize, Integer pageNumber) {
852
        return getTypeDesignations(name, status, pageSize, pageNumber, null);
853
    }
854

    
855
    @Override
856
    public Pager<TypeDesignationBase> getTypeDesignations(TaxonNameBase name, SpecimenTypeDesignationStatus status,
857
                Integer pageSize, Integer pageNumber, List<String> propertyPaths){
858
        Integer numberOfResults = dao.countTypeDesignations(name, status);
859

    
860
        List<TypeDesignationBase> results = new ArrayList<TypeDesignationBase>();
861
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
862
            results = dao.getTypeDesignations(name, status, pageSize, pageNumber, propertyPaths);
863
        }
864

    
865
        return new DefaultPagerImpl<TypeDesignationBase>(pageNumber, numberOfResults, pageSize, results);
866
    }
867

    
868
    /**
869
     * FIXME Candidate for harmonization
870
     * rename search
871
     */
872
    @Override
873
    public Pager<TaxonNameBase> searchNames(String uninomial,String infraGenericEpithet, String specificEpithet, String infraspecificEpithet, Rank rank, Integer pageSize,	Integer pageNumber, List<OrderHint> orderHints,
874
            List<String> propertyPaths) {
875
        Integer numberOfResults = dao.countNames(uninomial, infraGenericEpithet, specificEpithet, infraspecificEpithet, rank);
876

    
877
        List<TaxonNameBase> results = new ArrayList<TaxonNameBase>();
878
        if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
879
            results = dao.searchNames(uninomial, infraGenericEpithet, specificEpithet, infraspecificEpithet, rank, pageSize, pageNumber, orderHints, propertyPaths);
880
        }
881

    
882
        return new DefaultPagerImpl<TaxonNameBase>(pageNumber, numberOfResults, pageSize, results);
883
    }
884

    
885
    /* (non-Javadoc)
886
     * @see eu.etaxonomy.cdm.api.service.INameService#getUuidAndTitleCacheOfNames()
887
     */
888
    @Override
889
    public List<UuidAndTitleCache> getUuidAndTitleCacheOfNames() {
890
        return dao.getUuidAndTitleCacheOfNames();
891
    }
892

    
893
    @Override
894
    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) {
895
        Integer numberOfResults = dao.countByName(clazz, queryString, matchmode, criteria);
896

    
897
         List<TaxonNameBase> results = new ArrayList<TaxonNameBase>();
898
         if(numberOfResults > 0) { // no point checking again  //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
899
                results = dao.findByName(clazz, queryString, matchmode, criteria, pageSize, pageNumber, orderHints, propertyPaths);
900
         }
901

    
902
          return new DefaultPagerImpl<TaxonNameBase>(pageNumber, numberOfResults, pageSize, results);
903
    }
904

    
905
    @Override
906
    public HomotypicalGroup findHomotypicalGroup(UUID uuid) {
907
        return homotypicalGroupDao.findByUuid(uuid);
908
    }
909

    
910

    
911
    /* (non-Javadoc)
912
     * @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
913
     */
914
    @Override
915
    @Transactional(readOnly = false)
916
    public void updateTitleCache(Class<? extends TaxonNameBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<TaxonNameBase> cacheStrategy, IProgressMonitor monitor) {
917
        if (clazz == null){
918
            clazz = TaxonNameBase.class;
919
        }
920
        super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
921
    }
922

    
923

    
924
    @Override
925
    protected void setOtherCachesNull(TaxonNameBase name) {
926
        if (name.isInstanceOf(NonViralName.class)){
927
            NonViralName<?> nvn = CdmBase.deproxy(name, NonViralName.class);
928
            if (! nvn.isProtectedNameCache()){
929
                nvn.setNameCache(null, false);
930
            }
931
            if (! nvn.isProtectedAuthorshipCache()){
932
                nvn.setAuthorshipCache(null, false);
933
            }
934
            if (! nvn.isProtectedFullTitleCache()){
935
                nvn.setFullTitleCache(null, false);
936
            }
937
        }
938
    }
939

    
940
    /* (non-Javadoc)
941
     * @see eu.etaxonomy.cdm.api.service.INameService#getTaggedName(eu.etaxonomy.cdm.model.name.TaxonNameBase)
942
     */
943
    @Override
944
    public List<TaggedText> getTaggedName(UUID uuid) {
945
        TaxonNameBase taxonNameBase = dao.load(uuid);
946
        List taggedName = taxonNameBase.getTaggedName();
947
        return taggedName;
948
    }
949

    
950

    
951
}
(66-66/81)