Project

General

Profile

« Previous | Next » 

Revision 57f064a1

Added by Andreas Müller almost 8 years ago

Simplify taxonDao

View differences:

cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/persistence/dao/hibernate/taxon/TaxonDaoHibernateImpl.java
1
/**
2
 * Copyright (C) 2007 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9
package eu.etaxonomy.cdm.persistence.dao.hibernate.taxon;
10

  
11
import java.util.ArrayList;
12
import java.util.Collection;
13
import java.util.Collections;
14
import java.util.Comparator;
15
import java.util.HashSet;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.Set;
19
import java.util.SortedSet;
20
import java.util.TreeSet;
21
import java.util.UUID;
22

  
23
import org.apache.log4j.Logger;
24
import org.hibernate.Criteria;
25
import org.hibernate.FetchMode;
26
import org.hibernate.Hibernate;
27
import org.hibernate.Query;
28
import org.hibernate.Session;
29
import org.hibernate.criterion.Criterion;
30
import org.hibernate.criterion.Order;
31
import org.hibernate.criterion.Projections;
32
import org.hibernate.criterion.Restrictions;
33
import org.hibernate.envers.query.AuditEntity;
34
import org.hibernate.envers.query.AuditQuery;
35
import org.hibernate.search.FullTextSession;
36
import org.hibernate.search.Search;
37
import org.springframework.beans.factory.annotation.Autowired;
38
import org.springframework.beans.factory.annotation.Qualifier;
39
import org.springframework.dao.DataAccessException;
40
import org.springframework.stereotype.Repository;
41

  
42
import eu.etaxonomy.cdm.model.common.CdmBase;
43
import eu.etaxonomy.cdm.model.common.DefinedTerm;
44
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
45
import eu.etaxonomy.cdm.model.common.LSID;
46
import eu.etaxonomy.cdm.model.common.OriginalSourceBase;
47
import eu.etaxonomy.cdm.model.common.RelationshipBase;
48
import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
49
import eu.etaxonomy.cdm.model.location.NamedArea;
50
import eu.etaxonomy.cdm.model.name.NonViralName;
51
import eu.etaxonomy.cdm.model.name.Rank;
52
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
53
import eu.etaxonomy.cdm.model.name.TaxonNameComparator;
54
import eu.etaxonomy.cdm.model.reference.Reference;
55
import eu.etaxonomy.cdm.model.taxon.Classification;
56
import eu.etaxonomy.cdm.model.taxon.Synonym;
57
import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
58
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
59
import eu.etaxonomy.cdm.model.taxon.Taxon;
60
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
61
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
62
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
63
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
64
import eu.etaxonomy.cdm.model.view.AuditEvent;
65
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;
66
import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
67
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
68
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
69
import eu.etaxonomy.cdm.persistence.fetch.CdmFetch;
70
import eu.etaxonomy.cdm.persistence.query.MatchMode;
71
import eu.etaxonomy.cdm.persistence.query.OrderHint;
72

  
73

  
74
/**
75
 * @author a.mueller
76
 * @created 24.11.2008
77
 */
78
@Repository
79
@Qualifier("taxonDaoHibernateImpl")
80
public class TaxonDaoHibernateImpl extends IdentifiableDaoBase<TaxonBase> implements ITaxonDao {
81
//    private AlternativeSpellingSuggestionParser<TaxonBase> alternativeSpellingSuggestionParser;
82
    private static final Logger logger = Logger.getLogger(TaxonDaoHibernateImpl.class);
83

  
84
    public TaxonDaoHibernateImpl() {
85
        super(TaxonBase.class);
86
        indexedClasses = new Class[2];
87
        indexedClasses[0] = Taxon.class;
88
        indexedClasses[1] = Synonym.class;
89
        super.defaultField = "name.titleCache_tokenized";
90
    }
91

  
92
    @Autowired
93
    private ITaxonNameDao taxonNameDao;
94

  
95
////    spelling support currently disabled in appcontext, see spelling.xml ... "
96
////    @Autowired(required = false)   //TODO switched of because it caused problems when starting CdmApplicationController
97
//    public void setAlternativeSpellingSuggestionParser(AlternativeSpellingSuggestionParser<TaxonBase> alternativeSpellingSuggestionParser) {
98
//        this.alternativeSpellingSuggestionParser = alternativeSpellingSuggestionParser;
99
//    }
100

  
101
    @Override
102
    public List<Taxon> getRootTaxa(Reference sec) {
103
        return getRootTaxa(sec, CdmFetch.FETCH_CHILDTAXA(), true, false);
104
    }
105

  
106
    @Override
107
    public List<Taxon> getRootTaxa(Rank rank, Reference sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications, List<String> propertyPaths) {
108
        checkNotInPriorView("TaxonDaoHibernateImpl.getRootTaxa(Rank rank, Reference sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications)");
109
        if (onlyWithChildren == null){
110
            onlyWithChildren = true;
111
        }
112
        if (withMisapplications == null){
113
            withMisapplications = true;
114
        }
115
        if (cdmFetch == null){
116
            cdmFetch = CdmFetch.NO_FETCH();
117
        }
118

  
119
        Criteria crit = getSession().createCriteria(Taxon.class);
120

  
121
        crit.setFetchMode("name", FetchMode.JOIN);
122
        crit.createAlias("name", "name");
123

  
124
        if (rank != null) {
125
            crit.add(Restrictions.eq("name.rank", rank));
126
        }else{
127
            crit.add(Restrictions.isNull("taxonomicParentCache"));
128
        }
129

  
130
        if (sec != null){
131
            crit.add(Restrictions.eq("sec", sec) );
132
        }
133

  
134
        if (! cdmFetch.includes(CdmFetch.FETCH_CHILDTAXA())){
135
            logger.info("Not fetching child taxa");
136
            //TODO overwrite LAZY (SELECT) does not work (bug in hibernate?)
137
            crit.setFetchMode("relationsToThisTaxon.fromTaxon", FetchMode.LAZY);
138
        }
139

  
140
        List<Taxon> results = new ArrayList<Taxon>();
141
        List<Taxon> taxa = crit.list();
142
        for(Taxon taxon : taxa){
143

  
144

  
145
            //childTaxa
146
            //TODO create restriction instead
147
            // (a) not using cache fields
148
            /*Hibernate.initialize(taxon.getRelationsFromThisTaxon());
149
            if (onlyWithChildren == false || taxon.getRelationsFromThisTaxon().size() > 0){
150
                if (withMisapplications == true || ! taxon.isMisappliedName()){
151
                    defaultBeanInitializer.initialize(taxon, propertyPaths);
152
                    results.add(taxon);
153
                }
154
            }*/
155
            // (b) using cache fields
156
            if (onlyWithChildren == false || taxon.hasTaxonomicChildren()){
157
                if (withMisapplications == true || ! taxon.isMisapplication()){
158
                    defaultBeanInitializer.initialize(taxon, propertyPaths);
159
                    results.add(taxon);
160
                }
161
            }
162
        }
163
        return results;
164
    }
165

  
166
    @Override
167
    public List<Taxon> getRootTaxa(Reference sec, CdmFetch cdmFetch, Boolean onlyWithChildren, Boolean withMisapplications) {
168
        return getRootTaxa(null, sec, cdmFetch, onlyWithChildren, withMisapplications, null);
169
    }
170

  
171
    @Override
172
    public List<TaxonBase> getTaxaByName(String queryString, Reference sec) {
173

  
174
        return getTaxaByName(queryString, true, sec);
175
    }
176

  
177
    @Override
178
    public List<TaxonBase> getTaxaByName(String queryString, Boolean accepted, Reference sec) {
179
        checkNotInPriorView("TaxonDaoHibernateImpl.getTaxaByName(String name, Reference sec)");
180

  
181
        Criteria criteria = null;
182
        if (accepted == true) {
183
            criteria = getSession().createCriteria(Taxon.class);
184
        } else {
185
            criteria = getSession().createCriteria(Synonym.class);
186
        }
187

  
188
        criteria.setFetchMode( "name", FetchMode.JOIN );
189
        criteria.createAlias("name", "name");
190

  
191
        if (sec != null && sec.getId() != 0) {
192
            criteria.add(Restrictions.eq("sec", sec ) );
193
        }
194

  
195
        if (queryString != null) {
196
            criteria.add(Restrictions.ilike("name.nameCache", queryString));
197
        }
198

  
199
        return criteria.list();
200
    }
201

  
202
    public List<TaxonBase> getTaxaByName(boolean doTaxa, boolean doSynonyms, String queryString, MatchMode matchMode,
203
            Integer pageSize, Integer pageNumber) {
204

  
205
        return getTaxaByName(doTaxa, doSynonyms, false, queryString, null, matchMode, null, pageSize, pageNumber, null);
206
    }
207

  
208
    @Override
209
    public List<TaxonBase> getTaxaByName(String queryString, MatchMode matchMode,
210
            Boolean accepted, Integer pageSize, Integer pageNumber) {
211

  
212
        boolean doTaxa = true;
213
        boolean doSynonyms = true;
214

  
215
        if (accepted == true) {
216
            doSynonyms = false;
217
        } else {
218
           doTaxa = false;
219
        }
220
        return getTaxaByName(doTaxa, doSynonyms, queryString, matchMode, pageSize, pageNumber);
221
    }
222

  
223
    @Override
224
    public List<TaxonBase> getTaxaByName(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames,String queryString, Classification classification,
225
            MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize,
226
            Integer pageNumber, List<String> propertyPaths) {
227

  
228
        boolean doCount = false;
229

  
230
        Query query = prepareTaxaByName(doTaxa, doSynonyms, doMisappliedNames, "nameCache", queryString, classification, matchMode, namedAreas, pageSize, pageNumber, doCount);
231

  
232
        if (query != null){
233
            @SuppressWarnings("unchecked")
234
            List<TaxonBase> results = query.list();
235

  
236
            defaultBeanInitializer.initializeAll(results, propertyPaths);
237
            //TaxonComparatorSearch comp = new TaxonComparatorSearch();
238
            //Collections.sort(results, comp);
239
            return results;
240
        }
241

  
242
        return new ArrayList<TaxonBase>();
243

  
244
    }
245

  
246

  
247
    //new search for the editor, for performance issues the return values are only uuid and titleCache, to avoid the initialisation of all objects
248
    @Override
249
    @SuppressWarnings("unchecked")
250
    public List<UuidAndTitleCache<IdentifiableEntity>> getTaxaByNameForEditor(boolean doTaxa, boolean doSynonyms, boolean doNamesWithoutTaxa, boolean doMisappliedNames, String queryString, Classification classification,
251
            MatchMode matchMode, Set<NamedArea> namedAreas) {
252
//        long zstVorher;
253
//        long zstNachher;
254

  
255
        boolean doCount = false;
256
        List<UuidAndTitleCache<IdentifiableEntity>> resultObjects = new ArrayList<UuidAndTitleCache<IdentifiableEntity>>();
257
        if (doNamesWithoutTaxa){
258
        	List<? extends TaxonNameBase<?,?>> nameResult = taxonNameDao.findByName(queryString,matchMode, null, null, null, null);
259

  
260
        	for (TaxonNameBase name: nameResult){
261
        		if (name.getTaxonBases().size() == 0){
262
        			resultObjects.add(new UuidAndTitleCache(TaxonNameBase.class, name.getUuid(), name.getId(), name.getTitleCache()));
263
        		}
264
        	}
265
        	if (!doSynonyms && !doTaxa){
266
        		return resultObjects;
267
        	}
268
        }
269
        Query query = prepareTaxaByNameForEditor(doTaxa, doSynonyms, doMisappliedNames, "nameCache", queryString, classification, matchMode, namedAreas, doCount);
270

  
271

  
272
        if (query != null){
273
            List<Object[]> results = query.list();
274

  
275
            Object[] result;
276
            for(int i = 0; i<results.size();i++){
277
                result = results.get(i);
278

  
279
                //differentiate taxa and synonyms
280
                // new Boolean(result[3].toString()) is due to the fact that result[3] could be a Boolean ora String
281
                // see FIXME in 'prepareQuery' for more details
282
                if (doTaxa && doSynonyms){
283
                    if (result[3].equals("synonym")) {
284
                        resultObjects.add( new UuidAndTitleCache(Synonym.class, (UUID) result[0], (Integer) result[1], (String)result[2], new Boolean(result[4].toString())));
285
                    }
286
                    else {
287
                        resultObjects.add( new UuidAndTitleCache(Taxon.class, (UUID) result[0], (Integer) result[1], (String)result[2], new Boolean(result[4].toString())));
288
                    }
289
                }else if (doTaxa){
290
                        resultObjects.add( new UuidAndTitleCache(Taxon.class, (UUID) result[0], (Integer) result[1], (String)result[2], new Boolean(result[4].toString())));
291
                }else if (doSynonyms){
292
                    resultObjects.add( new UuidAndTitleCache(Synonym.class, (UUID) result[0], (Integer) result[1], (String)result[2], new Boolean(result[4].toString())));
293
                }
294
            }
295

  
296

  
297

  
298
        }
299

  
300
        return resultObjects;
301

  
302
    }
303

  
304
    @Override
305
    public List<Taxon> getTaxaByCommonName(String queryString, Classification classification,
306
               MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize,
307
               Integer pageNumber, List<String> propertyPaths) {
308
        boolean doCount = false;
309
        Query query = prepareTaxaByCommonName(queryString, classification, matchMode, namedAreas, pageSize, pageNumber, doCount, false);
310
        if (query != null){
311
            List<Taxon> results = query.list();
312
            defaultBeanInitializer.initializeAll(results, propertyPaths);
313
            return results;
314
        }
315
        return new ArrayList<Taxon>();
316

  
317
    }
318

  
319
    /**
320
     * @param clazz
321
     * @param searchField the field in TaxonNameBase to be searched through usually either <code>nameCache</code> or <code>titleCache</code>
322
     * @param queryString
323
     * @param classification TODO
324
     * @param matchMode
325
     * @param namedAreas
326
     * @param pageSize
327
     * @param pageNumber
328
     * @param doCount
329
     * @return
330
     *
331
     *
332
     */
333
    private Query prepareTaxaByNameForEditor(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, String searchField, String queryString, Classification classification,
334
            MatchMode matchMode, Set<NamedArea> namedAreas, boolean doCount) {
335
        return prepareQuery(doTaxa, doSynonyms, doMisappliedNames, searchField, queryString,
336
                classification, matchMode, namedAreas, doCount, true);
337
    }
338

  
339
    /**
340
     * @param searchField
341
     * @param queryString
342
     * @param classification
343
     * @param matchMode
344
     * @param namedAreas
345
     * @param doCount
346
     * @param doNotReturnFullEntities
347
     *            if set true the seach method will not return synonym and taxon
348
     *            entities but an array containing the uuid, titleCache, and the
349
     *            DTYPE in lowercase letters.
350
     * @param clazz
351
     * @return
352
     */
353
    private Query prepareQuery(boolean doTaxa, boolean doSynonyms, boolean doIncludeMisappliedNames, String searchField, String queryString,
354
                Classification classification, MatchMode matchMode, Set<NamedArea> namedAreas, boolean doCount, boolean doNotReturnFullEntities){
355

  
356
            String hqlQueryString = matchMode.queryStringFrom(queryString);
357
            String selectWhat;
358
            if (doNotReturnFullEntities){
359
                selectWhat = "t.uuid, t.id, t.titleCache ";
360
            }else {
361
                selectWhat = (doCount ? "count(t)": "t");
362
            }
363

  
364
            String hql = "";
365
            Set<NamedArea> areasExpanded = new HashSet<NamedArea>();
366
            if(namedAreas != null && namedAreas.size() > 0){
367
                // expand areas and restrict by distribution area
368
                Query areaQuery = getSession().createQuery("select childArea from NamedArea as childArea left join childArea.partOf as parentArea where parentArea = :area");
369
                expandNamedAreas(namedAreas, areasExpanded, areaQuery);
370
            }
371
            boolean doAreaRestriction = areasExpanded.size() > 0;
372

  
373
            Set<UUID> namedAreasUuids = new HashSet<UUID>();
374
            for (NamedArea area:areasExpanded){
375
                namedAreasUuids.add(area.getUuid());
376
            }
377

  
378

  
379
            String [] subSelects = createHQLString(doTaxa, doSynonyms, doIncludeMisappliedNames, classification, areasExpanded, matchMode, searchField);
380
            String taxonSubselect = subSelects[1];
381
            String synonymSubselect = subSelects[2];
382
            String misappliedSelect = subSelects[0];
383

  
384

  
385
            /*if(classification != null ){
386
                if (!doIncludeMisappliedNames){
387
                    if(doAreaRestriction){
388

  
389
                        taxonSubselect = "select t.id from" +
390
                            " Distribution e" +
391
                            " join e.inDescription d" +
392
                            " join d.taxon t" +
393
                            " join t.name n " +
394
                            " join t.taxonNodes as tn "+
395
                            " where" +
396
                            " e.area.uuid in (:namedAreasUuids) AND" +
397
                            " tn.classification = :classification" +
398
                            " AND n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
399

  
400

  
401

  
402
                        synonymSubselect = "select s.id from" +
403
                            " Distribution e" +
404
                            " join e.inDescription d" +
405
                            " join d.taxon t" + // the taxa
406
                            " join t.taxonNodes as tn "+
407
                            " join t.synonymRelations sr" +
408
                            " join sr.relatedFrom s" + // the synonyms
409
                            " join s.name sn"+
410
                            " where" +
411
                            " e.area.uuid in (:namedAreasUuids) AND" +
412
                            " tn.classification = :classification" +
413
                            " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
414

  
415
                    } else {
416

  
417
                        taxonSubselect = "select t.id from" +
418
                            " Taxon t" +
419
                            " join t.name n " +
420
                            " join t.taxonNodes as tn "+
421
                            " where" +
422
                            " tn.classification = :classification" +
423
                            " AND n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
424

  
425
                        synonymSubselect = "select s.id from" +
426
                            " Taxon t" + // the taxa
427
                            " join t.taxonNodes as tn "+
428
                            " join t.synonymRelations sr" +
429
                            " join sr.relatedFrom s" + // the synonyms
430
                            " join s.name sn"+
431
                            " where" +
432
                            " tn.classification = :classification" +
433
                            " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
434
                    }
435
                }else{
436
                    if(doAreaRestriction){
437
                        if (!doTaxa && !doSynonyms ){
438
                            misappliedSelect = "select t.id from" +
439
                            " Distribution e" +
440
                            " join e.inDescription d" +
441
                            " join d.taxon t" +
442
                            " join t.name n " +
443
                            " join t.taxonNodes as tn "+
444
                            " left join t.relationsFromThisTaxon as rft" +
445
                            " left join rft.relatedTo as rt" +
446
                            " left join rt.taxonNodes as tn2" +
447
                            " left join rt.name as n2" +
448
                            " left join rft.type as rtype"+
449
                            " where" +
450
                            " e.area.uuid in (:namedAreasUuids) AND" +
451
                            " (tn.classification != :classification" +
452
                            " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString" +
453
                            " AND tn2.classification = :classification" +
454
                            " AND rtype = :rType )";
455

  
456
                        }else{
457
                            taxonSubselect = "select t.id from" +
458
                                " Distribution e" +
459
                                " join e.inDescription d" +
460
                                " join d.taxon t" +
461
                                " join t.name n " +
462
                                " join t.taxonNodes as tn "+
463
                                " left join t.relationsFromThisTaxon as rft" +
464
                                " left join rft.relatedTo as rt" +
465
                                " left join rt.taxonNodes as tn2" +
466
                                " left join rt.name as n2" +
467
                                " left join rft.type as rtype"+
468
                                " where" +
469
                                " e.area.uuid in (:namedAreasUuids) AND" +
470
                                " (tn.classification = :classification" +
471
                                " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString )" +
472
                                " OR"+
473
                                " (tn.classification != :classification" +
474
                                " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString" +
475
                                " AND tn2.classification = :classification" +
476
                                " AND rtype = :rType )";
477

  
478

  
479
                            synonymSubselect = "select s.id from" +
480
                                " Distribution e" +
481
                                " join e.inDescription d" +
482
                                " join d.taxon t" + // the taxa
483
                                " join t.taxonNodes as tn "+
484
                                " join t.synonymRelations sr" +
485
                                " join sr.relatedFrom s" + // the synonyms
486
                                " join s.name sn"+
487
                                " where" +
488
                                " e.area.uuid in (:namedAreasUuids) AND" +
489
                                " tn.classification != :classification" +
490
                                " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
491
                        }
492
                    } else {
493
                        if (!doTaxa && !doSynonyms ){
494
                            misappliedSelect = "select t.id from" +
495
                            " Distribution e" +
496
                            " join e.inDescription d" +
497
                            " join d.taxon t" +
498
                            " join t.name n " +
499
                            " join t.taxonNodes as tn "+
500
                            " left join t.relationsFromThisTaxon as rft" +
501
                            " left join rft.relatedTo as rt" +
502
                            " left join rt.taxonNodes as tn2" +
503
                            " left join rt.name as n2" +
504
                            " left join rft.type as rtype"+
505
                            " where" +
506
                            " (tn.classification != :classification" +
507
                            " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString" +
508
                            " AND tn2.classification = :classification" +
509
                            " AND rtype = :rType )";
510

  
511
                        }else{
512
                            taxonSubselect = "select t.id from" +
513
                                " Taxon t" +
514
                                " join t.name n " +
515
                                " join t.taxonNodes as tn "+
516
                                " left join t.relationsFromThisTaxon as rft" +
517
                                " left join rft.relatedTo as rt" +
518
                                " left join rt.taxonNodes as tn2" +
519
                                " left join rt.name as n2" +
520
                                " left join rft.type as rtype"+
521
                                " where " +
522
                                " (tn.classification = :classification" +
523
                                " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString )" +
524
                                " OR"+
525
                                " (tn.classification != :classification" +
526
                                " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString" +
527
                                " AND tn2.classification = :classification" +
528
                                " AND rtype = :rType )";
529

  
530
                            synonymSubselect = "select s.id from" +
531
                                " Taxon t" + // the taxa
532
                                " join t.taxonNodes as tn "+
533
                                " join t.synonymRelations sr" +
534
                                " join sr.relatedFrom s" + // the synonyms
535
                                " join s.name sn"+
536
                                " where" +
537
                                " tn.classification != :classification" +
538
                                " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
539
                        }
540
                    }
541
                }
542
            } else {
543

  
544
                if (!doIncludeMisappliedNames){
545
                    if(doAreaRestriction){
546
                        taxonSubselect = "select t.id from " +
547
                            " Distribution e" +
548
                            " join e.inDescription d" +
549
                            " join d.taxon t" +
550
                            " join t.name n "+
551
                            " where" +
552
                            (doAreaRestriction ? " e.area.uuid in (:namedAreasUuids) AND" : "") +
553
                            " n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
554

  
555
                        synonymSubselect = "select s.id from" +
556
                            " Distribution e" +
557
                            " join e.inDescription d" +
558
                            " join d.taxon t" + // the taxa
559
                            " join t.synonymRelations sr" +
560
                            " join sr.relatedFrom s" + // the synonyms
561
                            " join s.name sn"+
562
                            " where" +
563
                            (doAreaRestriction ? " e.area.uuid in (:namedAreasUuids) AND" : "") +
564
                            " sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
565

  
566
                    } else {
567

  
568
                        taxonSubselect = "select t.id from " +
569
                            " Taxon t" +
570
                            " join t.name n "+
571
                            " where" +
572
                            " n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
573

  
574
                        synonymSubselect = "select s.id from" +
575
                            " Taxon t" + // the taxa
576
                            " join t.synonymRelations sr" +
577
                            " join sr.relatedFrom s" + // the synonyms
578
                            " join s.name sn"+
579
                            " where" +
580
                            " sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
581
                    }
582
                }else{
583

  
584
                }
585

  
586
            }*/
587

  
588
            logger.debug("taxonSubselect: " + taxonSubselect != null ? taxonSubselect: "NULL");
589
            logger.debug("synonymSubselect: " + synonymSubselect != null ? synonymSubselect: "NULL");
590

  
591
            Query subTaxon = null;
592
            Query subSynonym = null;
593
            Query subMisappliedNames = null;
594
            if(doTaxa){
595
                // find Taxa
596
                subTaxon = getSession().createQuery(taxonSubselect).setParameter("queryString", hqlQueryString);
597

  
598
                if(doAreaRestriction){
599
                    subTaxon.setParameterList("namedAreasUuids", namedAreasUuids);
600
                }
601
                if(classification != null){
602
                    subTaxon.setParameter("classification", classification);
603

  
604
                }
605

  
606

  
607
            }
608

  
609
            if(doSynonyms){
610
                // find synonyms
611
                subSynonym = getSession().createQuery(synonymSubselect).setParameter("queryString", hqlQueryString);
612

  
613
                if(doAreaRestriction){
614
                    subSynonym.setParameterList("namedAreasUuids", namedAreasUuids);
615
                }
616
                if(classification != null){
617
                    subSynonym.setParameter("classification", classification);
618
                }
619
            }
620
            if (doIncludeMisappliedNames ){
621
                subMisappliedNames = getSession().createQuery(misappliedSelect).setParameter("queryString", hqlQueryString);
622
                subMisappliedNames.setParameter("rType", TaxonRelationshipType.MISAPPLIED_NAME_FOR());
623
                if(doAreaRestriction){
624
                    subMisappliedNames.setParameterList("namedAreasUuids", namedAreasUuids);
625
                }
626
                if(classification != null){
627
                    subMisappliedNames.setParameter("classification", classification);
628
                }
629
            }
630

  
631
            List<Integer> taxa = new ArrayList<Integer>();
632
            List<Integer> synonyms = new ArrayList<Integer>();
633
            if (doSynonyms){
634
                synonyms = subSynonym.list();
635
            }
636
            if(doTaxa){
637
                taxa = subTaxon.list();
638
            }
639
            if (doIncludeMisappliedNames){
640
                taxa.addAll(subMisappliedNames.list());
641
            }
642

  
643
            //FIXME : the fourth element of the result should be a boolean, but in the case of a synonym
644
            // (which does require a check) a constant boolean (false) value needs to set. It seems that
645
            // hql cannot parse a constant boolean value in the select list clause. This implies that the
646
            // resulting object could be a Boolean or a String. The workaround for this is to convert the
647
            // resutling object into a String (using toString) and then create a new Boolean object from
648
            // String.
649
            if (doTaxa && doSynonyms){
650
                if(synonyms.size()>0 && taxa.size()>0){
651
                    hql = "select " + selectWhat;
652
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
653
                    // also return the computed isOrphaned flag
654
                    if (doNotReturnFullEntities &&  !doCount ){
655
                        hql += ", case when t.id in (:taxa) then 'taxon' else 'synonym' end, " +
656
                                " case when t.id in (:taxa) and t.taxonNodes is empty and t.relationsFromThisTaxon is empty and t.relationsToThisTaxon is empty then true else false end ";
657
                    }
658
                    hql +=  " from %s t " +
659
                            " where (t.id in (:taxa) OR t.id in (:synonyms)) ";
660
                }else if (synonyms.size()>0 ){
661
                    hql = "select " + selectWhat;
662
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
663
                    // also return the computed isOrphaned flag
664
                    if (doNotReturnFullEntities &&  !doCount ){
665
                        hql += ", 'synonym', 'false' ";
666

  
667
                    }
668
                    hql +=  " from %s t " +
669
                            " where t.id in (:synonyms) ";
670

  
671
                } else if (taxa.size()>0 ){
672
                    hql = "select " + selectWhat;
673
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
674
                    // also return the computed isOrphaned flag
675
                    if (doNotReturnFullEntities &&  !doCount ){
676
                        hql += ", 'taxon', " +
677
                                " case when t.taxonNodes is empty and t.relationsFromThisTaxon is empty and t.relationsToThisTaxon is empty then true else false end ";
678
                    }
679
                    hql +=  " from %s t " +
680
                            " where t.id in (:taxa) ";
681

  
682
                } else{
683
                    hql = "select " + selectWhat + " from %s t";
684
                }
685
            } else if(doTaxa){
686
                if  (taxa.size()>0){
687
                    hql = "select " + selectWhat;
688
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
689
                    // also return the computed isOrphaned flag
690
                    if (doNotReturnFullEntities){
691
                        hql += ", 'taxon', " +
692
                                " case when t.taxonNodes is empty and t.relationsFromThisTaxon is empty and t.relationsToThisTaxon is empty then true else false end ";
693
                    }
694
                    hql +=  " from %s t " +
695
                            " where t.id in (:taxa) ";
696

  
697
                }else{
698
                    hql = "select " + selectWhat + " from %s t";
699
                }
700
            } else if(doSynonyms){
701
                if (synonyms.size()>0){
702

  
703
                    hql = "select " + selectWhat;
704
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
705
                    // also return the computed isOrphaned flag
706
                    if (doNotReturnFullEntities){
707
                        hql += ", 'synonym', 'false' ";
708
                    }
709
                    hql +=  " from %s t " +
710
                            " where t.id in (:synonyms) ";
711
                }else{
712
                    hql = "select " + selectWhat + " from %s t";
713
                }
714
            } else if (doIncludeMisappliedNames){
715
                hql = "select " + selectWhat;
716
                // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
717
                // also return the computed isOrphaned flag
718
                if (doNotReturnFullEntities){
719
                    hql += ", 'taxon', " +
720
                            " case when t.taxonNodes is empty and t.relationsFromThisTaxon is empty and t.relationsToThisTaxon is empty then true else false end ";
721
                }
722
                hql +=  " from %s t " +
723
                        " where t.id in (:taxa) ";
724

  
725
            }
726

  
727
            String classString;
728
            if (doTaxa && doSynonyms){
729
                classString = "TaxonBase";
730
            } else if (doTaxa){
731
                classString = "Taxon";
732
            } else if (doSynonyms){
733
                classString = "Synonym";
734
            } else{//only misappliedNames
735
                classString = "Taxon";
736
            }
737

  
738
            hql = String.format(hql, classString);
739

  
740

  
741
            if (hql == "") {
742
                return null;
743
            }
744
            if(!doCount){
745
                hql += " order by t.name.genusOrUninomial, case when t.name.specificEpithet like '\"%\"' then 1 else 0 end, t.name.specificEpithet, t.name.rank desc, t.name.nameCache";
746
            }
747

  
748
            logger.debug("hql: " + hql);
749
            Query query = getSession().createQuery(hql);
750

  
751

  
752
            if (doTaxa && doSynonyms){
753
                // find taxa and synonyms
754
                if (taxa.size()>0){
755
                    query.setParameterList("taxa", taxa);
756
                }
757
                if (synonyms.size()>0){
758
                    query.setParameterList("synonyms",synonyms);
759
                }
760
                if (taxa.size()== 0 && synonyms.size() == 0){
761
                    return null;
762
                }
763
            }else if(doTaxa){
764
                //find taxa
765
                if (taxa.size()>0){
766
                    query.setParameterList("taxa", taxa );
767
                }else{
768
                    logger.warn("there are no taxa for the query: " + queryString);
769
                    return null;
770
                }
771
            } else if(doSynonyms){
772
                // find synonyms
773
                if (synonyms.size()>0){
774
                    query.setParameterList("synonyms", synonyms);
775
                }else{
776
                    return null;
777
                }
778
            }	else{
779
                //only misappliedNames
780
                if (taxa.size()>0){
781
                    query.setParameterList("taxa", taxa );
782
                }else{
783
                    return null;
784
                }
785
            }
786

  
787
            return query;
788
    }
789

  
790

  
791
    /**
792
     * @param searchField the field in TaxonNameBase to be searched through usually either <code>nameCache</code> or <code>titleCache</code>
793
     * @param queryString
794
     * @param classification TODO
795
     * @param matchMode
796
     * @param namedAreas
797
     * @param pageSize
798
     * @param pageNumber
799
     * @param doCount
800
     * @param clazz
801
     * @return
802
     *
803
     * FIXME implement classification restriction & implement test: see {@link TaxonDaoHibernateImplTest#testCountTaxaByName()}
804
     */
805
    private Query prepareTaxaByName(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, String searchField, String queryString,
806
            Classification classification, MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize, Integer pageNumber, boolean doCount) {
807

  
808
        Query query = prepareQuery(doTaxa, doSynonyms, doMisappliedNames, searchField, queryString, classification, matchMode, namedAreas, doCount, false);
809

  
810
        if(pageSize != null &&  !doCount && query != null) {
811
            query.setMaxResults(pageSize);
812
            if(pageNumber != null) {
813
                query.setFirstResult(pageNumber * pageSize);
814
            }
815
        }
816

  
817
        return query;
818
    }
819

  
820
    private Query prepareTaxaByCommonName(String queryString, Classification classification,
821
            MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize, Integer pageNumber, boolean doCount, boolean doNotReturnFullEntities){
822

  
823
        String what = "select";
824
        if (doNotReturnFullEntities){
825
        	what += " t.uuid, t.id, t.titleCache, \'taxon\', case when t.taxonNodes is empty and t.relationsFromThisTaxon is empty and t.relationsToThisTaxon is empty then true else false end ";
826
        }else {
827
        	what += (doCount ? " count(t)": " t");
828
        }
829
        String hql= what + " from Taxon t " +
830
        "join t.descriptions d "+
831
        "join d.descriptionElements e " +
832
        "join e.feature f " +
833
        "where f.supportsCommonTaxonName = true and e.name "+matchMode.getMatchOperator()+" :queryString";//and ls.text like 'common%'";
834

  
835
        Query query = getSession().createQuery(hql);
836

  
837
        query.setParameter("queryString", matchMode.queryStringFrom(queryString));
838

  
839
        if(pageSize != null &&  !doCount) {
840
            query.setMaxResults(pageSize);
841
            if(pageNumber != null) {
842
                query.setFirstResult(pageNumber * pageSize);
843
            }
844
        }
845
        return query;
846
    }
847

  
848
    @Override
849
    public long countTaxaByName(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, String queryString, Classification classification,
850
        MatchMode matchMode, Set<NamedArea> namedAreas) {
851

  
852
        boolean doCount = true;
853
        /*
854
        boolean doTaxa = true;
855
        boolean doSynonyms = true;
856
        if (clazz.equals(Taxon.class)){
857
            doSynonyms = false;
858
        } else if (clazz.equals(Synonym.class)){
859
            doTaxa = false;
860
        }
861
        */
862

  
863

  
864
        Query query = prepareTaxaByName(doTaxa, doSynonyms, doMisappliedNames, "nameCache", queryString, classification, matchMode, namedAreas, null, null, doCount);
865
        if (query != null) {
866
            return (Long)query.uniqueResult();
867
        }else{
868
            return 0;
869
        }
870
    }
871

  
872
    /**
873
     * @param namedAreas
874
     * @param areasExpanded
875
     * @param areaQuery
876
     */
877
    private void expandNamedAreas(Collection<NamedArea> namedAreas, Set<NamedArea> areasExpanded, Query areaQuery) {
878
        List<NamedArea> childAreas;
879
        for(NamedArea a : namedAreas){
880
            areasExpanded.add(a);
881
            areaQuery.setParameter("area", a);
882
            childAreas = areaQuery.list();
883
            if(childAreas.size() > 0){
884
                areasExpanded.addAll(childAreas);
885
                expandNamedAreas(childAreas, areasExpanded, areaQuery);
886
            }
887
        }
888
    }
889

  
890

  
891
    @Override
892
    public List<TaxonBase> getAllTaxonBases(Integer pagesize, Integer page) {
893
        return super.list(pagesize, page);
894
    }
895

  
896
    @Override
897
    public List<Synonym> getAllSynonyms(Integer limit, Integer start) {
898
        Criteria criteria = getSession().createCriteria(Synonym.class);
899

  
900
        if(limit != null) {
901
            criteria.setFirstResult(start);
902
            criteria.setMaxResults(limit);
903
        }
904

  
905
        return criteria.list();
906
    }
907

  
908
    @Override
909
    public List<Taxon> getAllTaxa(Integer limit, Integer start) {
910
        Criteria criteria = getSession().createCriteria(Taxon.class);
911

  
912
        if(limit != null) {
913
            criteria.setFirstResult(start);
914
            criteria.setMaxResults(limit);
915
        }
916

  
917
        return criteria.list();
918
    }
919

  
920
    @Override
921
    public List<RelationshipBase> getAllRelationships(/*Class<? extends RelationshipBase> clazz,*/ Integer limit, Integer start) {
922
        Class<? extends RelationshipBase> clazz = RelationshipBase.class;  //preliminary, see #2653
923
        AuditEvent auditEvent = getAuditEventFromContext();
924
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
925
            // for some reason the HQL .class discriminator didn't work here so I created this preliminary
926
            // implementation for now. Should be cleaned in future.
927

  
928
            List<RelationshipBase> result = new ArrayList<RelationshipBase>();
929

  
930
            int taxRelSize = countAllRelationships(TaxonRelationship.class);
931

  
932
            if (taxRelSize > start){
933

  
934
                String hql = " FROM TaxonRelationship as rb ORDER BY rb.id ";
935
                Query query = getSession().createQuery(hql);
936
                query.setFirstResult(start);
937
                if (limit != null){
938
                    query.setMaxResults(limit);
939
                }
940
                result = query.list();
941
            }
942
            limit = limit - result.size();
943
            if (limit > 0){
944
                String hql = " FROM SynonymRelationship as rb ORDER BY rb.id ";
945
                Query query = getSession().createQuery(hql);
946
                start = (taxRelSize > start) ? 0 : (start - taxRelSize);
947
                query.setFirstResult(start);
948
                if (limit != null){
949
                    query.setMaxResults(limit);
950
                }
951
                result.addAll(query.list());
952
            }
953
            return result;
954

  
955
        } else {
956
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(clazz,auditEvent.getRevisionNumber());
957
            return query.getResultList();
958
        }
959
    }
960

  
961
    @Override
962
    public UUID delete(TaxonBase taxonBase) throws DataAccessException{
963
        if (taxonBase == null){
964
            logger.warn("TaxonBase was 'null'");
965
            return null;
966
        }
967

  
968
        // Merge the object in if it is detached
969
        //
970
        // I think this is preferable to catching lazy initialization errors
971
        // as that solution only swallows and hides the exception, but doesn't
972
        // actually solve it.
973
        getSession().merge(taxonBase);
974

  
975
        taxonBase.removeSources();
976

  
977
        if (taxonBase instanceof Taxon){ //	is Taxon
978
            for (Iterator<TaxonRelationship> iterator = ((Taxon)taxonBase).getRelationsFromThisTaxon().iterator(); iterator.hasNext();){
979
                TaxonRelationship relationFromThisTaxon = iterator.next();
980

  
981
                // decrease children count of taxonomic parent by one
982
                if (relationFromThisTaxon.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())) {
983
                    Taxon toTaxon = relationFromThisTaxon.getToTaxon(); // parent
984
                    if (toTaxon != null) {
985
                        toTaxon.setTaxonomicChildrenCount(toTaxon.getTaxonomicChildrenCount() - 1);
986
                    }
987
                }
988
            }
989
        }
990

  
991
       return super.delete(taxonBase);
992

  
993
    }
994

  
995
    @Override
996
    public List<TaxonBase> findByNameTitleCache(boolean doTaxa, boolean doSynonyms, String queryString, Classification classification, MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageNumber, Integer pageSize, List<String> propertyPaths) {
997

  
998
        boolean doCount = false;
999
        Query query = prepareTaxaByName(doTaxa, doSynonyms, false, "titleCache", queryString, classification, matchMode, namedAreas, pageSize, pageNumber, doCount);
1000
        if (query != null){
1001
            List<TaxonBase> results = query.list();
1002
            defaultBeanInitializer.initializeAll(results, propertyPaths);
1003
            return results;
1004
        }
1005
        return new ArrayList<TaxonBase>();
1006

  
1007
    }
1008

  
1009
    @Override
1010
    public TaxonBase findByUuid(UUID uuid, List<Criterion> criteria, List<String> propertyPaths) {
1011

  
1012
        Criteria crit = getSession().createCriteria(type);
1013

  
1014
        if (uuid != null) {
1015
            crit.add(Restrictions.eq("uuid", uuid));
1016
        } else {
1017
            logger.warn("UUID is NULL");
1018
            return null;
1019
        }
1020
        if(criteria != null){
1021
            for (Criterion criterion : criteria) {
1022
                crit.add(criterion);
1023
            }
1024
        }
1025
        crit.addOrder(Order.asc("uuid"));
1026

  
1027
        List<? extends TaxonBase> results = crit.list();
1028
        if (results.size() == 1) {
1029
            defaultBeanInitializer.initializeAll(results, propertyPaths);
1030
            TaxonBase taxon = results.iterator().next();
1031
            return taxon;
1032
        } else if (results.size() > 1) {
1033
            logger.error("Multiple results for UUID: " + uuid);
1034
        } else if (results.size() == 0) {
1035
            logger.info("No results for UUID: " + uuid);
1036
        }
1037

  
1038
        return null;
1039
    }
1040

  
1041
    @Override
1042
    public List<? extends TaxonBase> findByUuids(List<UUID> uuids, List<Criterion> criteria, List<String> propertyPaths) {
1043

  
1044
        Criteria crit = getSession().createCriteria(type);
1045

  
1046
        if (uuids != null) {
1047
            crit.add(Restrictions.in("uuid", uuids));
1048
        } else {
1049
            logger.warn("List<UUID> uuids is NULL");
1050
            return null;
1051
        }
1052
        if(criteria != null){
1053
            for (Criterion criterion : criteria) {
1054
                crit.add(criterion);
1055
            }
1056
        }
1057
        crit.addOrder(Order.asc("uuid"));
1058

  
1059
        List<? extends TaxonBase> results = crit.list();
1060

  
1061
        defaultBeanInitializer.initializeAll(results, propertyPaths);
1062
        return results;
1063
    }
1064

  
1065
    @Override
1066
    public int countMatchesByName(String queryString, MatchMode matchMode, boolean onlyAcccepted) {
1067
        checkNotInPriorView("TaxonDaoHibernateImpl.countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted)");
1068
        Criteria crit = getSession().createCriteria(type);
1069
        crit.add(Restrictions.ilike("titleCache", matchMode.queryStringFrom(queryString)));
1070
        crit.setProjection(Projections.rowCount());
1071
        int result = ((Number)crit.list().get(0)).intValue();
1072
        return result;
1073
    }
1074

  
1075

  
1076
    @Override
1077
    public int countMatchesByName(String queryString, MatchMode matchMode, boolean onlyAcccepted, List<Criterion> criteria) {
1078
        checkNotInPriorView("TaxonDaoHibernateImpl.countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted, List<Criterion> criteria)");
1079
        Criteria crit = getSession().createCriteria(type);
1080
        crit.add(Restrictions.ilike("titleCache", matchMode.queryStringFrom(queryString)));
1081
        if(criteria != null){
1082
            for (Criterion criterion : criteria) {
1083
                crit.add(criterion);
1084
            }
1085
        }
1086
        crit.setProjection(Projections.rowCount());
1087
        int result = ((Number)crit.list().get(0)).intValue();
1088
        return result;
1089
    }
1090

  
1091
    @Override
1092
    public int countTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Direction direction) {
1093
        AuditEvent auditEvent = getAuditEventFromContext();
1094
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1095
            Query query = null;
1096

  
1097
            if(type == null) {
1098
                query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship."+direction+" = :relatedTaxon");
1099
            } else {
1100
                query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship."+direction+" = :relatedTaxon and taxonRelationship.type = :type");
1101
                query.setParameter("type",type);
1102
            }
1103
            query.setParameter("relatedTaxon", taxon);
1104

  
1105
            return ((Long)query.uniqueResult()).intValue();
1106
        } else {
1107
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());
1108
            query.add(AuditEntity.relatedId(direction.toString()).eq(taxon.getId()));
1109
            query.addProjection(AuditEntity.id().count());
1110

  
1111
            if(type != null) {
1112
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1113
            }
1114

  
1115
            return ((Long)query.getSingleResult()).intValue();
1116
        }
1117
    }
1118

  
1119
    @Override
1120
    public int countSynonyms(Taxon taxon, SynonymRelationshipType type) {
1121
        AuditEvent auditEvent = getAuditEventFromContext();
1122
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1123
            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);
1124

  
1125
            criteria.add(Restrictions.eq("relatedTo", taxon));
1126
            if(type != null) {
1127
                criteria.add(Restrictions.eq("type", type));
1128
            }
1129
            criteria.setProjection(Projections.rowCount());
1130
            return ((Number)criteria.uniqueResult()).intValue();
1131
        } else {
1132
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());
1133
            query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));
1134
            query.addProjection(AuditEntity.id().count());
1135

  
1136
            if(type != null) {
1137
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1138
            }
1139

  
1140
            return ((Long)query.getSingleResult()).intValue();
1141
        }
1142
    }
1143

  
1144
    @Override
1145
    public int countSynonyms(Synonym synonym, SynonymRelationshipType type) {
1146
        AuditEvent auditEvent = getAuditEventFromContext();
1147
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1148
            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);
1149

  
1150
            criteria.add(Restrictions.eq("relatedFrom", synonym));
1151
            if(type != null) {
1152
                criteria.add(Restrictions.eq("type", type));
1153
            }
1154

  
1155
            criteria.setProjection(Projections.rowCount());
1156
            return ((Number)criteria.uniqueResult()).intValue();
1157
        } else {
1158
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());
1159
            query.add(AuditEntity.relatedId("relatedFrom").eq(synonym.getId()));
1160
            query.addProjection(AuditEntity.id().count());
1161

  
1162
            if(type != null) {
1163
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1164
            }
1165

  
1166
            return ((Long)query.getSingleResult()).intValue();
1167
        }
1168
    }
1169

  
1170
    @Override
1171
    public int countTaxaByName(Class<? extends TaxonBase> clazz, String genusOrUninomial, String infraGenericEpithet, String specificEpithet,	String infraSpecificEpithet, Rank rank) {
1172
        checkNotInPriorView("TaxonDaoHibernateImpl.countTaxaByName(Boolean accepted, String genusOrUninomial,	String infraGenericEpithet, String specificEpithet,	String infraSpecificEpithet, Rank rank)");
1173
        Criteria criteria = null;
1174

  
1175
        criteria = getSession().createCriteria(clazz);
1176

  
1177
        criteria.setFetchMode( "name", FetchMode.JOIN );
1178
        criteria.createAlias("name", "name");
1179

  
1180
        if(genusOrUninomial == null) {
1181
            criteria.add(Restrictions.isNull("name.genusOrUninomial"));
1182
        } else if(!genusOrUninomial.equals("*")) {
1183
            criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));
1184
        }
1185

  
1186
        if(infraGenericEpithet == null) {
1187
            criteria.add(Restrictions.isNull("name.infraGenericEpithet"));
1188
        } else if(!infraGenericEpithet.equals("*")) {
1189
            criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));
1190
        }
1191

  
1192
        if(specificEpithet == null) {
1193
            criteria.add(Restrictions.isNull("name.specificEpithet"));
1194
        } else if(!specificEpithet.equals("*")) {
1195
            criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));
1196

  
1197
        }
1198

  
1199
        if(infraSpecificEpithet == null) {
1200
            criteria.add(Restrictions.isNull("name.infraSpecificEpithet"));
1201
        } else if(!infraSpecificEpithet.equals("*")) {
1202
            criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));
1203
        }
1204

  
1205
        if(rank != null) {
1206
            criteria.add(Restrictions.eq("name.rank", rank));
1207
        }
1208

  
1209
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
1210

  
1211
        return ((Number)criteria.uniqueResult()).intValue();
1212
    }
1213

  
1214
    @Override
1215
    public List<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, Rank rank, Integer pageSize,	Integer pageNumber) {
1216
        checkNotInPriorView("TaxonDaoHibernateImpl.findTaxaByName(Boolean accepted, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, Rank rank, Integer pageSize,	Integer pageNumber)");
1217
        Criteria criteria = null;
1218
        if (clazz == null){
1219
            criteria = getSession().createCriteria(TaxonBase.class);
1220
        } else{
1221
            criteria = getSession().createCriteria(clazz);
1222
        }
1223
        criteria.setFetchMode( "name", FetchMode.JOIN );
1224
        criteria.createAlias("name", "name");
1225

  
1226
        if(genusOrUninomial == null) {
1227
            criteria.add(Restrictions.isNull("name.genusOrUninomial"));
1228
        } else if(!genusOrUninomial.equals("*")) {
1229
            criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));
1230
        }
1231

  
1232
        if(infraGenericEpithet == null) {
1233
            criteria.add(Restrictions.isNull("name.infraGenericEpithet"));
1234
        } else if(!infraGenericEpithet.equals("*")) {
1235
            criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));
1236
        }
1237

  
1238
        if(specificEpithet == null) {
1239
            criteria.add(Restrictions.isNull("name.specificEpithet"));
1240
        } else if(!specificEpithet.equals("*")) {
1241
            criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));
1242

  
1243
        }
1244

  
1245
        if(infraSpecificEpithet == null) {
1246
            criteria.add(Restrictions.isNull("name.infraSpecificEpithet"));
1247
        } else if(!infraSpecificEpithet.equals("*")) {
1248
            criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));
1249
        }
1250

  
1251
        if(rank != null) {
1252
            criteria.add(Restrictions.eq("name.rank", rank));
1253
        }
1254

  
1255
        if(pageSize != null) {
1256
            criteria.setMaxResults(pageSize);
1257
            if(pageNumber != null) {
1258
                criteria.setFirstResult(pageNumber * pageSize);
1259
            } else {
1260
                criteria.setFirstResult(0);
1261
            }
1262
        }
1263

  
1264
        return criteria.list();
1265
    }
1266

  
1267
    @Override
1268
    public List<TaxonRelationship> getTaxonRelationships(Taxon taxon, TaxonRelationshipType type,
1269
            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths, Direction direction) {
1270

  
1271
        AuditEvent auditEvent = getAuditEventFromContext();
1272
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1273

  
1274
            Criteria criteria = getSession().createCriteria(TaxonRelationship.class);
1275

  
1276
            if(direction != null) {
1277
                criteria.add(Restrictions.eq(direction.name(), taxon));
1278
            } else {
1279
                criteria.add(Restrictions.or(
1280
                        Restrictions.eq(Direction.relatedFrom.name(), taxon),
1281
                        Restrictions.eq(Direction.relatedTo.name(), taxon))
1282
                    );
1283
            }
1284

  
1285
            if(type != null) {
1286
                criteria.add(Restrictions.eq("type", type));
1287
            }
1288

  
1289
            addOrder(criteria,orderHints);
1290

  
1291
            if(pageSize != null) {
1292
                criteria.setMaxResults(pageSize);
1293
                if(pageNumber != null) {
1294
                    criteria.setFirstResult(pageNumber * pageSize);
1295
                } else {
1296
                    criteria.setFirstResult(0);
1297
                }
1298
            }
1299

  
1300
            List<TaxonRelationship> result = criteria.list();
1301
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1302

  
1303
            return result;
1304
        } else {
1305
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());
1306
            query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));
1307

  
1308
            if(type != null) {
1309
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1310
            }
1311

  
1312
            if(pageSize != null) {
1313
                query.setMaxResults(pageSize);
1314
                if(pageNumber != null) {
1315
                    query.setFirstResult(pageNumber * pageSize);
1316
                } else {
1317
                    query.setFirstResult(0);
1318
                }
1319
            }
1320

  
1321
            List<TaxonRelationship> result = query.getResultList();
1322
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1323

  
1324
            // Ugly, but for now, there is no way to sort on a related entity property in Envers,
1325
            // and we can't live without this functionality in CATE as it screws up the whole
1326
            // taxon tree thing
1327
            if(orderHints != null && !orderHints.isEmpty()) {
1328
                SortedSet<TaxonRelationship> sortedList = new TreeSet<TaxonRelationship>(new TaxonRelationshipFromTaxonComparator());
1329
                sortedList.addAll(result);
1330
                return new ArrayList<TaxonRelationship>(sortedList);
1331
            }
1332

  
1333
            return result;
1334
        }
1335
    }
1336

  
1337
    class TaxonRelationshipFromTaxonComparator implements Comparator<TaxonRelationship> {
1338

  
1339
        @Override
1340
        public int compare(TaxonRelationship o1, TaxonRelationship o2) {
1341
            return o1.getFromTaxon().getTitleCache().compareTo(o2.getFromTaxon().getTitleCache());
1342
        }
1343

  
1344
    }
1345

  
1346
    class SynonymRelationshipFromTaxonComparator implements Comparator<SynonymRelationship> {
1347

  
1348
        @Override
1349
        public int compare(SynonymRelationship o1, SynonymRelationship o2) {
1350
            return o1.getSynonym().getTitleCache().compareTo(o2.getSynonym().getTitleCache());
1351
        }
1352

  
1353
    }
1354

  
1355
    @Override
1356
    public List<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
1357
        AuditEvent auditEvent = getAuditEventFromContext();
1358
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1359
            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);
1360

  
1361
            criteria.add(Restrictions.eq("relatedTo", taxon));
1362
            if(type != null) {
1363
                criteria.add(Restrictions.eq("type", type));
1364
            }
1365

  
1366
            addOrder(criteria,orderHints);
1367

  
1368
            if(pageSize != null) {
1369
                criteria.setMaxResults(pageSize);
1370
                if(pageNumber != null) {
1371
                    criteria.setFirstResult(pageNumber * pageSize);
1372
                } else {
1373
                    criteria.setFirstResult(0);
1374
                }
1375
            }
1376

  
1377
            List<SynonymRelationship> result = criteria.list();
1378
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1379

  
1380
            return result;
1381
        } else {
1382
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());
1383
            query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));
1384

  
1385
            if(type != null) {
1386
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1387
            }
1388

  
1389
            if(pageSize != null) {
1390
                query.setMaxResults(pageSize);
1391
                if(pageNumber != null) {
1392
                    query.setFirstResult(pageNumber * pageSize);
1393
                } else {
1394
                    query.setFirstResult(0);
1395
                }
1396
            }
1397

  
1398
            List<SynonymRelationship> result = query.getResultList();
1399
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1400

  
1401
            return result;
1402
        }
1403
    }
1404

  
1405
    @Override
1406
    public List<SynonymRelationship> getSynonyms(Synonym synonym, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
1407
        AuditEvent auditEvent = getAuditEventFromContext();
1408
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1409
            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);
1410

  
1411
            criteria.add(Restrictions.eq("relatedFrom", synonym));
1412
            if(type != null) {
1413
                criteria.add(Restrictions.eq("type", type));
1414
            }
1415

  
1416
            addOrder(criteria,orderHints);
1417

  
1418
            if(pageSize != null) {
1419
                criteria.setMaxResults(pageSize);
1420
                if(pageNumber != null) {
1421
                    criteria.setFirstResult(pageNumber * pageSize);
1422
                } else {
1423
                    criteria.setFirstResult(0);
1424
                }
1425
            }
1426

  
1427
            List<SynonymRelationship> result = criteria.list();
1428
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1429

  
1430
            return result;
1431
        } else {
1432
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());
1433
            query.add(AuditEntity.relatedId("relatedFrom").eq(synonym.getId()));
1434

  
1435
            if(type != null) {
1436
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1437
            }
1438

  
1439
            if(pageSize != null) {
1440
                query.setMaxResults(pageSize);
1441
                if(pageNumber != null) {
1442
                    query.setFirstResult(pageNumber * pageSize);
1443
                } else {
1444
                    query.setFirstResult(0);
1445
                }
1446
            }
1447

  
1448
            List<SynonymRelationship> result = query.getResultList();
1449
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1450

  
1451
            return result;
1452
        }
1453
    }
1454

  
1455
    @Override
1456
    public void rebuildIndex() {
1457
        FullTextSession fullTextSession = Search.getFullTextSession(getSession());
1458

  
1459
        for(TaxonBase taxonBase : list(null,null)) { // re-index all taxon base
1460
            Hibernate.initialize(taxonBase.getName());
1461
            fullTextSession.index(taxonBase);
1462
        }
1463
        fullTextSession.flushToIndexes();
1464
    }
1465

  
1466
    @Override
1467
    public String suggestQuery(String queryString) {
1468
        throw new RuntimeException("Query suggestion currently not implemented in TaxonDaoHibernateImpl");
1469
//        checkNotInPriorView("TaxonDaoHibernateImpl.suggestQuery(String queryString)");
1470
//        String alternativeQueryString = null;
1471
//        if (alternativeSpellingSuggestionParser != null) {
1472
//            try {
1473
//
1474
//                alternativeSpellingSuggestionParser.parse(queryString);
1475
//                org.apache.lucene.search.Query alternativeQuery = alternativeSpellingSuggestionParser.suggest(queryString);
1476
//                if (alternativeQuery != null) {
1477
//                    alternativeQueryString = alternativeQuery
1478
//                            .toString("name.titleCache");
1479
//                }
1480
//
1481
//            } catch (ParseException e) {
1482
//                throw new QueryParseException(e, queryString);
1483
//            }
1484
//        }
1485
//        return alternativeQueryString;
1486
    }
1487

  
1488
    @Override
1489
    public List<Taxon> listAcceptedTaxaFor(Synonym synonym, Classification classificationFilter, Integer pageSize, Integer pageNumber,
1490
            List<OrderHint> orderHints, List<String> propertyPaths){
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff