Project

General

Profile

Download (75.4 KB) Statistics
| Branch: | Tag: | Revision:
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.criterion.Criterion;
29
import org.hibernate.criterion.Order;
30
import org.hibernate.criterion.Projections;
31
import org.hibernate.criterion.Restrictions;
32
import org.hibernate.envers.query.AuditEntity;
33
import org.hibernate.envers.query.AuditQuery;
34
import org.hibernate.envers.query.criteria.internal.NotNullAuditExpression;
35
import org.hibernate.envers.query.internal.property.EntityPropertyName;
36
import org.hibernate.search.FullTextSession;
37
import org.hibernate.search.Search;
38
import org.springframework.beans.factory.annotation.Autowired;
39
import org.springframework.beans.factory.annotation.Qualifier;
40
import org.springframework.dao.DataAccessException;
41
import org.springframework.stereotype.Repository;
42

    
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.MarkerType;
47
import eu.etaxonomy.cdm.model.common.OriginalSourceBase;
48
import eu.etaxonomy.cdm.model.common.RelationshipBase.Direction;
49
import eu.etaxonomy.cdm.model.location.NamedArea;
50
import eu.etaxonomy.cdm.model.name.Rank;
51
import eu.etaxonomy.cdm.model.name.TaxonName;
52
import eu.etaxonomy.cdm.model.name.TaxonNameComparator;
53
import eu.etaxonomy.cdm.model.reference.Reference;
54
import eu.etaxonomy.cdm.model.taxon.Classification;
55
import eu.etaxonomy.cdm.model.taxon.Synonym;
56
import eu.etaxonomy.cdm.model.taxon.SynonymType;
57
import eu.etaxonomy.cdm.model.taxon.Taxon;
58
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
59
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
60
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
61
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
62
import eu.etaxonomy.cdm.model.view.AuditEvent;
63
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;
64
import eu.etaxonomy.cdm.persistence.dao.name.ITaxonNameDao;
65
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
66
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
67
import eu.etaxonomy.cdm.persistence.query.MatchMode;
68
import eu.etaxonomy.cdm.persistence.query.NameSearchOrder;
69
import eu.etaxonomy.cdm.persistence.query.OrderHint;
70
import eu.etaxonomy.cdm.persistence.query.TaxonTitleType;
71

    
72

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

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

    
91
    @Autowired
92
    private ITaxonNameDao taxonNameDao;
93

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

    
100

    
101
    @Override
102
    public List<TaxonBase> getTaxaByName(String queryString, Reference sec) {
103

    
104
        return getTaxaByName(queryString, true, sec);
105
    }
106

    
107
    @Override
108
    public List<TaxonBase> getTaxaByName(String queryString, Boolean accepted, Reference sec) {
109
        checkNotInPriorView("TaxonDaoHibernateImpl.getTaxaByName(String name, Reference sec)");
110

    
111
        Criteria criteria = null;
112
        if (accepted == true) {
113
            criteria = getSession().createCriteria(Taxon.class);
114
        } else {
115
            criteria = getSession().createCriteria(Synonym.class);
116
        }
117

    
118
        criteria.setFetchMode( "name", FetchMode.JOIN );
119
        criteria.createAlias("name", "name");
120

    
121
        if (sec != null && sec.getId() != 0) {
122
            criteria.add(Restrictions.eq("sec", sec ) );
123
        }
124

    
125
        if (queryString != null) {
126
            criteria.add(Restrictions.ilike("name.nameCache", queryString));
127
        }
128

    
129
        return criteria.list();
130
    }
131

    
132
    public List<TaxonBase> getTaxaByName(boolean doTaxa, boolean doSynonyms, String queryString, MatchMode matchMode,
133
            Integer pageSize, Integer pageNumber) {
134

    
135
        return getTaxaByName(doTaxa, doSynonyms, false, false, false, queryString, null, matchMode, null, null, pageSize, pageNumber, null);
136
    }
137

    
138
    @Override
139
    public List<TaxonBase> getTaxaByName(String queryString, MatchMode matchMode,
140
            Boolean accepted, Integer pageSize, Integer pageNumber) {
141

    
142
        boolean doTaxa = true;
143
        boolean doSynonyms = true;
144

    
145
        if (accepted == true) {
146
            doSynonyms = false;
147
        } else {
148
           doTaxa = false;
149
        }
150
        return getTaxaByName(doTaxa, doSynonyms, queryString, matchMode, pageSize, pageNumber);
151
    }
152

    
153
    @Override
154
    public List<TaxonBase> getTaxaByName(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, boolean doCommonNames,
155
            boolean includeAuthors,
156
            String queryString, Classification classification,
157
            MatchMode matchMode, Set<NamedArea> namedAreas, NameSearchOrder order,
158
            Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
159

    
160
        boolean doCount = false;
161

    
162
        String searchField = includeAuthors ? "titleCache" : "nameCache";
163
        Query query = prepareTaxaByName(doTaxa, doSynonyms, doMisappliedNames, doCommonNames, searchField, queryString, classification, matchMode, namedAreas, order, pageSize, pageNumber, doCount);
164

    
165
        if (query != null){
166
            @SuppressWarnings("unchecked")
167
            List<TaxonBase> results = query.list();
168

    
169
            defaultBeanInitializer.initializeAll(results, propertyPaths);
170

    
171
            //Collections.sort(results, comp);
172
            return results;
173
        }
174

    
175
        return new ArrayList<>();
176

    
177
    }
178

    
179

    
180
    //new search for the editor, for performance issues the return values are only uuid and titleCache, to avoid the initialisation of all objects
181
    @Override
182
    @SuppressWarnings("unchecked")
183
    public List<UuidAndTitleCache<IdentifiableEntity>> getTaxaByNameForEditor(boolean doTaxa, boolean doSynonyms, boolean doNamesWithoutTaxa, boolean doMisappliedNames, boolean doCommonNames, String queryString, Classification classification,
184
            MatchMode matchMode, Set<NamedArea> namedAreas, NameSearchOrder order) {
185
//        long zstVorher;
186
//        long zstNachher;
187
        if (order == null){
188
            order = NameSearchOrder.ALPHA;  //TODO add to signature
189
        }
190

    
191
        boolean doCount = false;
192
        boolean includeAuthors = false;
193
        List<UuidAndTitleCache<IdentifiableEntity>> resultObjects = new ArrayList<UuidAndTitleCache<IdentifiableEntity>>();
194
        if (doNamesWithoutTaxa){
195
        	List<? extends TaxonName<?,?>> nameResult = taxonNameDao.findByName(
196
        	        includeAuthors, queryString, matchMode, null, null, null, null);
197

    
198
        	for (TaxonName name: nameResult){
199
        		if (name.getTaxonBases().size() == 0){
200
        			resultObjects.add(new UuidAndTitleCache(TaxonName.class, name.getUuid(), name.getId(), name.getTitleCache()));
201
        		}
202
        	}
203
        	if (!doSynonyms && !doTaxa && !doCommonNames){
204
        		return resultObjects;
205
        	}
206
        }
207
        Query query = prepareTaxaByNameForEditor(doTaxa, doSynonyms, doMisappliedNames, doCommonNames, "nameCache", queryString, classification, matchMode, namedAreas, doCount, order);
208

    
209

    
210
        if (query != null){
211
            List<Object[]> results = query.list();
212

    
213
            Object[] result;
214
            for(int i = 0; i<results.size();i++){
215
                result = results.get(i);
216

    
217
                //differentiate taxa and synonyms
218
                // new Boolean(result[3].toString()) is due to the fact that result[3] could be a Boolean ora String
219
                // see FIXME in 'prepareQuery' for more details
220
                if (doTaxa || doSynonyms || doCommonNames){
221
                    if (result[3].equals("synonym")) {
222
                        resultObjects.add( new UuidAndTitleCache(Synonym.class, (UUID) result[0], (Integer) result[1], (String)result[2], new Boolean(result[4].toString()), null));
223
                    }
224
                    else {
225
                        resultObjects.add( new UuidAndTitleCache(Taxon.class, (UUID) result[0], (Integer) result[1], (String)result[2], new Boolean(result[4].toString()), null));
226
                    }
227

    
228
                }else if (doSynonyms){
229
                    resultObjects.add( new UuidAndTitleCache(Synonym.class, (UUID) result[0], (Integer) result[1], (String)result[2], new Boolean(result[4].toString()), null));
230
                }
231
            }
232

    
233

    
234

    
235
        }
236

    
237
        return resultObjects;
238

    
239
    }
240

    
241
    @Override
242
    public List<Taxon> getTaxaByCommonName(String queryString, Classification classification,
243
               MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize,
244
               Integer pageNumber, List<String> propertyPaths) {
245
        boolean doCount = false;
246
        Query query = prepareTaxaByCommonName(queryString, classification, matchMode, namedAreas, pageSize, pageNumber, doCount, false);
247
        if (query != null){
248
            List<Taxon> results = query.list();
249
            defaultBeanInitializer.initializeAll(results, propertyPaths);
250
            return results;
251
        }
252
        return new ArrayList<Taxon>();
253

    
254
    }
255

    
256
    /**
257
     * @param clazz
258
     * @param searchField the field in TaxonName to be searched through usually either <code>nameCache</code> or <code>titleCache</code>
259
     * @param queryString
260
     * @param classification TODO
261
     * @param matchMode
262
     * @param namedAreas
263
     * @param pageSize
264
     * @param pageNumber
265
     * @param doCount
266
     * @return
267
     *
268
     *
269
     */
270
    private Query prepareTaxaByNameForEditor(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, boolean doCommonNames,
271
            String searchField, String queryString, Classification classification,
272
            MatchMode matchMode, Set<NamedArea> namedAreas, boolean doCount, NameSearchOrder order) {
273
        return prepareQuery(doTaxa, doSynonyms, doMisappliedNames, doCommonNames, searchField, queryString,
274
                classification, matchMode, namedAreas, order, doCount, true);
275
    }
276

    
277
    /**
278
     * @param searchField
279
     * @param queryString
280
     * @param classification
281
     * @param matchMode
282
     * @param namedAreas
283
     * @param doCount
284
     * @param doNotReturnFullEntities
285
     *            if set true the seach method will not return synonym and taxon
286
     *            entities but an array containing the uuid, titleCache, and the
287
     *            DTYPE in lowercase letters.
288
     * @param order
289
     * @param clazz
290
     * @return
291
     */
292
    private Query prepareQuery(boolean doTaxa, boolean doSynonyms, boolean doIncludeMisappliedNames, boolean doCommonNames, String searchField, String queryString,
293
                Classification classification, MatchMode matchMode, Set<NamedArea> namedAreas, NameSearchOrder order, boolean doCount, boolean doNotReturnFullEntities){
294

    
295
            if (order == null){
296
                order = NameSearchOrder.DEFAULT();
297
            }
298
            String hqlQueryString = matchMode.queryStringFrom(queryString);
299
            String selectWhat;
300
            if (doNotReturnFullEntities){
301
                selectWhat = "t.uuid, t.id, t.titleCache ";
302
            }else {
303
                selectWhat = (doCount ? "count(t)": "t");
304
            }
305

    
306

    
307

    
308
            String hql = "";
309
            Set<NamedArea> areasExpanded = new HashSet<NamedArea>();
310
            if(namedAreas != null && namedAreas.size() > 0){
311
                // expand areas and restrict by distribution area
312
                Query areaQuery = getSession().createQuery("select childArea from NamedArea as childArea left join childArea.partOf as parentArea where parentArea = :area");
313
                expandNamedAreas(namedAreas, areasExpanded, areaQuery);
314
            }
315
            boolean doAreaRestriction = areasExpanded.size() > 0;
316

    
317
            Set<UUID> namedAreasUuids = new HashSet<UUID>();
318
            for (NamedArea area:areasExpanded){
319
                namedAreasUuids.add(area.getUuid());
320
            }
321

    
322

    
323
            String [] subSelects = createHQLString(doTaxa, doSynonyms, doIncludeMisappliedNames, classification, areasExpanded, matchMode, searchField);
324
            String taxonSubselect = subSelects[1];
325
            String synonymSubselect = subSelects[2];
326
            String misappliedSelect = subSelects[0];
327
            String commonNameSubSelect = subSelects[3];
328

    
329

    
330
            if (logger.isDebugEnabled()) {
331
                logger.debug("taxonSubselect: " + (taxonSubselect != null ? taxonSubselect: "NULL"));
332
            }
333
            if (logger.isDebugEnabled()) {
334
                logger.debug("synonymSubselect: " + (synonymSubselect != null ? synonymSubselect: "NULL"));
335
            }
336

    
337
            Query subTaxon = null;
338
            Query subSynonym = null;
339
            Query subMisappliedNames = null;
340
            Query subCommonNames = null;
341

    
342
            if(doTaxa){
343
                // find Taxa
344
                subTaxon = getSession().createQuery(taxonSubselect).setParameter("queryString", hqlQueryString);
345

    
346
                if(doAreaRestriction){
347
                    subTaxon.setParameterList("namedAreasUuids", namedAreasUuids);
348
                }
349
                if(classification != null){
350
                    subTaxon.setParameter("classification", classification);
351

    
352
                }
353
            }
354

    
355
            if(doSynonyms){
356
                // find synonyms
357
                subSynonym = getSession().createQuery(synonymSubselect).setParameter("queryString", hqlQueryString);
358

    
359
                if(doAreaRestriction){
360
                    subSynonym.setParameterList("namedAreasUuids", namedAreasUuids);
361
                }
362
                if(classification != null){
363
                    subSynonym.setParameter("classification", classification);
364
                }
365
            }
366
            if (doIncludeMisappliedNames ){
367
                subMisappliedNames = getSession().createQuery(misappliedSelect).setParameter("queryString", hqlQueryString);
368
                subMisappliedNames.setParameter("rType", TaxonRelationshipType.MISAPPLIED_NAME_FOR());
369
                if(doAreaRestriction){
370
                    subMisappliedNames.setParameterList("namedAreasUuids", namedAreasUuids);
371
                }
372
                if(classification != null){
373
                    subMisappliedNames.setParameter("classification", classification);
374
                }
375
            }
376

    
377
            if(doCommonNames){
378
                // find Taxa
379
                subCommonNames = getSession().createQuery(commonNameSubSelect).setParameter("queryString", hqlQueryString);
380

    
381
                if(doAreaRestriction){
382
                    subCommonNames.setParameterList("namedAreasUuids", namedAreasUuids);
383
                }
384
                if(classification != null){
385
                    subCommonNames.setParameter("classification", classification);
386
                }
387
            }
388

    
389
            List<Integer> taxa = new ArrayList<Integer>();
390
            List<Integer> synonyms = new ArrayList<Integer>();
391
            if (doSynonyms){
392
                synonyms = subSynonym.list();
393
            }
394
            if(doTaxa){
395
                taxa = subTaxon.list();
396
            }
397
            if (doIncludeMisappliedNames){
398
                taxa.addAll(subMisappliedNames.list());
399
            }
400
            if (doCommonNames){
401
                taxa.addAll(subCommonNames.list());
402
            }
403

    
404

    
405
           // if (doTaxa && doSynonyms){
406
                if(synonyms.size()>0 && taxa.size()>0){
407
                    hql = "select " + selectWhat;
408
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
409
                    // also return the computed isOrphaned flag
410
                    if (doNotReturnFullEntities &&  !doCount ){
411
                        hql += ", case when t.id in (:taxa) then 'taxon' else 'synonym' end, " +
412
                                " 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 ";
413
                    }
414
                    hql +=  " from %s t " +
415
                            " where (t.id in (:taxa) OR t.id in (:synonyms)) ";
416
                }else if (synonyms.size()>0 ){
417
                    hql = "select " + selectWhat;
418
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
419
                    // also return the computed isOrphaned flag
420
                    if (doNotReturnFullEntities &&  !doCount ){
421
                        hql += ", 'synonym', 'false' ";
422

    
423
                    }
424
                    hql +=  " from %s t " +
425
                            " where t.id in (:synonyms) ";
426

    
427
                } else if (taxa.size()>0 ){
428
                    hql = "select " + selectWhat;
429
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
430
                    // also return the computed isOrphaned flag
431
                    if (doNotReturnFullEntities &&  !doCount ){
432
                        hql += ", 'taxon', " +
433
                                " case when t.taxonNodes is empty and t.relationsFromThisTaxon is empty and t.relationsToThisTaxon is empty then true else false end ";
434
                    }
435
                    hql +=  " from %s t " +
436
                            " where t.id in (:taxa) ";
437

    
438
                } else{
439
                    hql = "select " + selectWhat + " from %s t";
440
                }
441

    
442
            String classString;
443
            if ((doTaxa || doCommonNames || doIncludeMisappliedNames) && doSynonyms){
444
                classString = "TaxonBase";
445
            } else if (doTaxa || doCommonNames){
446
                classString = "Taxon";
447
            } else if (doSynonyms && !(doCommonNames|| doTaxa || doIncludeMisappliedNames)){
448
                classString = "Synonym";
449
            } else{//only misappliedNames
450
                classString = "Taxon";
451
            }
452

    
453
            hql = String.format(hql, classString);
454

    
455

    
456
            if (hql == "") {
457
                return null;
458
            }
459
            if(!doCount){
460
                String orderBy = " ORDER BY ";
461
                String alphabeticBase = " t.name.genusOrUninomial, case when t.name.specificEpithet like '\"%\"' then 1 else 0 end, t.name.specificEpithet, t.name.rank desc, t.name.nameCache";
462

    
463
                if (order == NameSearchOrder.LENGTH_ALPHA_NAME){
464
                    orderBy += " length(t.name.nameCache), " + alphabeticBase;
465
                }else if (order == NameSearchOrder.LENGTH_ALPHA_TITLE){
466
                    orderBy += " length(t.name.titleCache), " + alphabeticBase;
467
                }else {
468
                    orderBy += alphabeticBase;
469
                }
470

    
471
                hql += orderBy;
472
            }
473

    
474
            if(logger.isDebugEnabled()){ logger.debug("hql: " + hql);}
475
            Query query = getSession().createQuery(hql);
476

    
477

    
478
            if ((doTaxa || doCommonNames || doIncludeMisappliedNames) ){
479
                // find taxa and synonyms
480
                if (taxa.size()>0){
481
                    query.setParameterList("taxa", taxa);
482
                }
483
                if (synonyms.size()>0){
484
                    query.setParameterList("synonyms",synonyms);
485
                }
486
                if (taxa.size()== 0 && synonyms.size() == 0){
487
                    return null;
488
                }
489
            }
490
            if(doSynonyms){
491
                // find synonyms
492
                if (synonyms.size()>0){
493
                    query.setParameterList("synonyms", synonyms);
494
                }
495
            }
496

    
497
            return query;
498
    }
499

    
500

    
501
    /**
502
     * @param searchField the field in TaxonName to be searched through usually either <code>nameCache</code> or <code>titleCache</code>
503
     * @param queryString
504
     * @param classification TODO
505
     * @param matchMode
506
     * @param namedAreas
507
     * @param pageSize
508
     * @param pageNumber
509
     * @param doCount
510
     * @param clazz
511
     * @return
512
     *
513
     * FIXME implement classification restriction & implement test: see {@link TaxonDaoHibernateImplTest#testCountTaxaByName()}
514
     */
515
    private Query prepareTaxaByName(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, boolean doCommonNames, String searchField, String queryString,
516
            Classification classification, MatchMode matchMode, Set<NamedArea> namedAreas, NameSearchOrder order, Integer pageSize, Integer pageNumber, boolean doCount) {
517

    
518
        Query query = prepareQuery(doTaxa, doSynonyms, doMisappliedNames, doCommonNames, searchField, queryString, classification, matchMode, namedAreas, order, doCount, false);
519

    
520
        if(pageSize != null &&  !doCount && query != null) {
521
            query.setMaxResults(pageSize);
522
            if(pageNumber != null) {
523
                query.setFirstResult(pageNumber * pageSize);
524
            }
525
        }
526

    
527
        return query;
528
    }
529

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

    
533
        String what = "select distinct";
534
        if (doNotReturnFullEntities){
535
        	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 ";
536
        }else {
537
        	what += (doCount ? " count(t)": " t");
538
        }
539
        String hql= what + " from Taxon t " +
540
        "join t.descriptions d "+
541
        "join d.descriptionElements e " +
542
        "join e.feature f " +
543
        "where f.supportsCommonTaxonName = true and e.name "+matchMode.getMatchOperator()+" :queryString";//and ls.text like 'common%'";
544

    
545
        Query query = getSession().createQuery(hql);
546

    
547
        query.setParameter("queryString", matchMode.queryStringFrom(queryString));
548

    
549
        if(pageSize != null &&  !doCount) {
550
            query.setMaxResults(pageSize);
551
            if(pageNumber != null) {
552
                query.setFirstResult(pageNumber * pageSize);
553
            }
554
        }
555
        return query;
556
    }
557

    
558
    @Override
559
    public long countTaxaByName(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, boolean doCommonNames,
560
            boolean doIncludeAuthors, String queryString, Classification classification,
561
        MatchMode matchMode, Set<NamedArea> namedAreas) {
562

    
563
        boolean doCount = true;
564
        /*
565
        boolean doTaxa = true;
566
        boolean doSynonyms = true;
567
        if (clazz.equals(Taxon.class)){
568
            doSynonyms = false;
569
        } else if (clazz.equals(Synonym.class)){
570
            doTaxa = false;
571
        }
572
        */
573
        String searchField = doIncludeAuthors ? "titleCache": "nameCache";
574

    
575
        Query query = prepareTaxaByName(doTaxa, doSynonyms, doMisappliedNames, doCommonNames, searchField, queryString, classification, matchMode, namedAreas, null, null, null, doCount);
576
        if (query != null) {
577
            return (Long)query.uniqueResult();
578
        }else{
579
            return 0;
580
        }
581
    }
582

    
583
    /**
584
     * @param namedAreas
585
     * @param areasExpanded
586
     * @param areaQuery
587
     */
588
    private void expandNamedAreas(Collection<NamedArea> namedAreas, Set<NamedArea> areasExpanded, Query areaQuery) {
589
        List<NamedArea> childAreas;
590
        for(NamedArea a : namedAreas){
591
            areasExpanded.add(a);
592
            areaQuery.setParameter("area", a);
593
            childAreas = areaQuery.list();
594
            if(childAreas.size() > 0){
595
                areasExpanded.addAll(childAreas);
596
                expandNamedAreas(childAreas, areasExpanded, areaQuery);
597
            }
598
        }
599
    }
600

    
601

    
602
    @Override
603
    public List<TaxonBase> getAllTaxonBases(Integer pagesize, Integer page) {
604
        return super.list(pagesize, page);
605
    }
606

    
607
    @Override
608
    public List<Synonym> getAllSynonyms(Integer limit, Integer start) {
609
        Criteria criteria = getSession().createCriteria(Synonym.class);
610

    
611
        if(limit != null) {
612
            criteria.setFirstResult(start);
613
            criteria.setMaxResults(limit);
614
        }
615

    
616
        return criteria.list();
617
    }
618

    
619
    @Override
620
    public List<Taxon> getAllTaxa(Integer limit, Integer start) {
621
        Criteria criteria = getSession().createCriteria(Taxon.class);
622

    
623
        if(limit != null) {
624
            criteria.setFirstResult(start);
625
            criteria.setMaxResults(limit);
626
        }
627

    
628
        return criteria.list();
629
    }
630

    
631

    
632
    @Override
633
    public UUID delete(TaxonBase taxonBase) throws DataAccessException{
634
        if (taxonBase == null){
635
            logger.warn("TaxonBase was 'null'");
636
            return null;
637
        }
638

    
639
        // Merge the object in if it is detached
640
        //
641
        // I think this is preferable to catching lazy initialization errors
642
        // as that solution only swallows and hides the exception, but doesn't
643
        // actually solve it.
644
        taxonBase = (TaxonBase)getSession().merge(taxonBase);
645

    
646
        taxonBase.removeSources();
647

    
648

    
649
        if (taxonBase instanceof Taxon){ // is Taxon
650
            Taxon taxon = ((Taxon)taxonBase);
651
            Set<Synonym> syns = new HashSet<>(taxon.getSynonyms());
652
            for (Synonym syn: syns){
653
                taxon.removeSynonym(syn);
654
            }
655
        }
656

    
657
       return super.delete(taxonBase);
658

    
659
    }
660

    
661
    @Override
662
    public List<TaxonBase> findByNameTitleCache(boolean doTaxa, boolean doSynonyms, String queryString, Classification classification, MatchMode matchMode, Set<NamedArea> namedAreas, NameSearchOrder order, Integer pageNumber, Integer pageSize, List<String> propertyPaths) {
663

    
664
        boolean doCount = false;
665
        Query query = prepareTaxaByName(doTaxa, doSynonyms, false, false, "titleCache", queryString, classification, matchMode, namedAreas, order, pageSize, pageNumber, doCount);
666
        if (query != null){
667
            List<TaxonBase> results = query.list();
668
            defaultBeanInitializer.initializeAll(results, propertyPaths);
669
            return results;
670
        }
671
        return new ArrayList<TaxonBase>();
672

    
673
    }
674

    
675
    @Override
676
    public TaxonBase findByUuid(UUID uuid, List<Criterion> criteria, List<String> propertyPaths) {
677

    
678
        Criteria crit = getSession().createCriteria(type);
679

    
680
        if (uuid != null) {
681
            crit.add(Restrictions.eq("uuid", uuid));
682
        } else {
683
            logger.warn("UUID is NULL");
684
            return null;
685
        }
686
        if(criteria != null){
687
            for (Criterion criterion : criteria) {
688
                crit.add(criterion);
689
            }
690
        }
691
        crit.addOrder(Order.asc("uuid"));
692

    
693
        List<? extends TaxonBase> results = crit.list();
694
        if (results.size() == 1) {
695
            defaultBeanInitializer.initializeAll(results, propertyPaths);
696
            TaxonBase taxon = results.iterator().next();
697
            return taxon;
698
        } else if (results.size() > 1) {
699
            logger.error("Multiple results for UUID: " + uuid);
700
        } else if (results.size() == 0) {
701
            logger.info("No results for UUID: " + uuid);
702
        }
703

    
704
        return null;
705
    }
706

    
707
    @Override
708
    public List<? extends TaxonBase> findByUuids(List<UUID> uuids, List<Criterion> criteria, List<String> propertyPaths) {
709

    
710
        Criteria crit = getSession().createCriteria(type);
711

    
712
        if (uuids != null) {
713
            crit.add(Restrictions.in("uuid", uuids));
714
        } else {
715
            logger.warn("List<UUID> uuids is NULL");
716
            return null;
717
        }
718
        if(criteria != null){
719
            for (Criterion criterion : criteria) {
720
                crit.add(criterion);
721
            }
722
        }
723
        crit.addOrder(Order.asc("uuid"));
724

    
725
        List<? extends TaxonBase> results = crit.list();
726

    
727
        defaultBeanInitializer.initializeAll(results, propertyPaths);
728
        return results;
729
    }
730

    
731
    @Override
732
    public int countMatchesByName(String queryString, MatchMode matchMode, boolean onlyAcccepted) {
733
        checkNotInPriorView("TaxonDaoHibernateImpl.countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted)");
734
        Criteria crit = getSession().createCriteria(type);
735
        crit.add(Restrictions.ilike("titleCache", matchMode.queryStringFrom(queryString)));
736
        crit.setProjection(Projections.rowCount());
737
        int result = ((Number)crit.list().get(0)).intValue();
738
        return result;
739
    }
740

    
741

    
742
    @Override
743
    public int countMatchesByName(String queryString, MatchMode matchMode, boolean onlyAcccepted, List<Criterion> criteria) {
744
        checkNotInPriorView("TaxonDaoHibernateImpl.countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted, List<Criterion> criteria)");
745
        Criteria crit = getSession().createCriteria(type);
746
        crit.add(Restrictions.ilike("titleCache", matchMode.queryStringFrom(queryString)));
747
        if(criteria != null){
748
            for (Criterion criterion : criteria) {
749
                crit.add(criterion);
750
            }
751
        }
752
        crit.setProjection(Projections.rowCount());
753
        int result = ((Number)crit.list().get(0)).intValue();
754
        return result;
755
    }
756

    
757
    @Override
758
    public int countTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Direction direction) {
759
        AuditEvent auditEvent = getAuditEventFromContext();
760
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
761
            Query query = null;
762

    
763
            if(type == null) {
764
                query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship."+direction+" = :relatedTaxon");
765
            } else {
766
                query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship."+direction+" = :relatedTaxon and taxonRelationship.type = :type");
767
                query.setParameter("type",type);
768
            }
769
            query.setParameter("relatedTaxon", taxon);
770

    
771
            return ((Long)query.uniqueResult()).intValue();
772
        } else {
773
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());
774
            query.add(AuditEntity.relatedId(direction.toString()).eq(taxon.getId()));
775
            query.addProjection(AuditEntity.id().count());
776

    
777
            if(type != null) {
778
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
779
            }
780

    
781
            return ((Long)query.getSingleResult()).intValue();
782
        }
783
    }
784

    
785

    
786
    @Override
787
    public int countSynonyms(boolean onlyAttachedToTaxon) {
788
        AuditEvent auditEvent = getAuditEventFromContext();
789
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
790
            Query query = null;
791

    
792
            String queryStr = "SELECT count(syn) FROM Synonym syn";
793
            if (onlyAttachedToTaxon){
794
                queryStr += " WHERE syn.acceptedTaxon IS NOT NULL";
795
            }
796
            query = getSession().createQuery(queryStr);
797

    
798
            return ((Long)query.uniqueResult()).intValue();
799
        } else {
800
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(Synonym.class,auditEvent.getRevisionNumber());
801
            if (onlyAttachedToTaxon){
802
                query.add(new NotNullAuditExpression(new EntityPropertyName("acceptedTaxon")));
803
            }
804
            query.addProjection(AuditEntity.id().count());
805

    
806
            return ((Long)query.getSingleResult()).intValue();
807
        }
808
    }
809

    
810
    @Override
811
    public long countSynonyms(Taxon taxon, SynonymType type) {
812
        AuditEvent auditEvent = getAuditEventFromContext();
813
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
814
            Criteria criteria = getSession().createCriteria(Synonym.class);
815

    
816
            criteria.add(Restrictions.eq("acceptedTaxon", taxon));
817
            if(type != null) {
818
                criteria.add(Restrictions.eq("type", type));
819
            }
820
            criteria.setProjection(Projections.rowCount());
821
            return ((Number)criteria.uniqueResult()).intValue();
822
        } else {
823
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(Synonym.class,auditEvent.getRevisionNumber());
824
            query.add(AuditEntity.relatedId("acceptedTaxon").eq(taxon.getId()));
825
            query.addProjection(AuditEntity.id().count());
826

    
827
            if(type != null) {
828
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
829
            }
830

    
831
            return (Long)query.getSingleResult();
832
        }
833
    }
834

    
835
    @Override
836
    public int countSynonyms(Synonym synonym, SynonymType type) {
837
        AuditEvent auditEvent = getAuditEventFromContext();
838
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
839
            Criteria criteria = getSession().createCriteria(Synonym.class);
840

    
841
            criteria.add(Restrictions.isNotNull("acceptedTaxon"));
842
            if(type != null) {
843
                criteria.add(Restrictions.eq("type", type));
844
            }
845

    
846
            criteria.setProjection(Projections.rowCount());
847
            return ((Number)criteria.uniqueResult()).intValue();
848
        } else {
849
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(Synonym.class,auditEvent.getRevisionNumber());
850
            query.add(new NotNullAuditExpression(new EntityPropertyName("acceptedTaxon")));
851
            query.addProjection(AuditEntity.id().count());
852

    
853
            if(type != null) {
854
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
855
            }
856

    
857
            return ((Long)query.getSingleResult()).intValue();
858
        }
859
    }
860

    
861
    @Override
862
    public int countTaxaByName(Class<? extends TaxonBase> clazz, String genusOrUninomial, String infraGenericEpithet, String specificEpithet,	String infraSpecificEpithet, Rank rank) {
863
        checkNotInPriorView("TaxonDaoHibernateImpl.countTaxaByName(Boolean accepted, String genusOrUninomial,	String infraGenericEpithet, String specificEpithet,	String infraSpecificEpithet, Rank rank)");
864
        Criteria criteria = null;
865

    
866
        criteria = getSession().createCriteria(clazz);
867

    
868
        criteria.setFetchMode( "name", FetchMode.JOIN );
869
        criteria.createAlias("name", "name");
870

    
871
        if(genusOrUninomial == null) {
872
            criteria.add(Restrictions.isNull("name.genusOrUninomial"));
873
        } else if(!genusOrUninomial.equals("*")) {
874
            criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));
875
        }
876

    
877
        if(infraGenericEpithet == null) {
878
            criteria.add(Restrictions.isNull("name.infraGenericEpithet"));
879
        } else if(!infraGenericEpithet.equals("*")) {
880
            criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));
881
        }
882

    
883
        if(specificEpithet == null) {
884
            criteria.add(Restrictions.isNull("name.specificEpithet"));
885
        } else if(!specificEpithet.equals("*")) {
886
            criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));
887

    
888
        }
889

    
890
        if(infraSpecificEpithet == null) {
891
            criteria.add(Restrictions.isNull("name.infraSpecificEpithet"));
892
        } else if(!infraSpecificEpithet.equals("*")) {
893
            criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));
894
        }
895

    
896
        if(rank != null) {
897
            criteria.add(Restrictions.eq("name.rank", rank));
898
        }
899

    
900
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
901

    
902
        return ((Number)criteria.uniqueResult()).intValue();
903
    }
904

    
905
    @Override
906
    public List<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, String authorship, Rank rank, Integer pageSize,	Integer pageNumber) {
907
        checkNotInPriorView("TaxonDaoHibernateImpl.findTaxaByName(Boolean accepted, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, String authorship, Rank rank, Integer pageSize,	Integer pageNumber)");
908
        Criteria criteria = null;
909
        if (clazz == null){
910
            criteria = getSession().createCriteria(TaxonBase.class);
911
        } else{
912
            criteria = getSession().createCriteria(clazz);
913
        }
914
        criteria.setFetchMode( "name", FetchMode.JOIN );
915
        criteria.createAlias("name", "name");
916

    
917
        if(genusOrUninomial == null) {
918
            criteria.add(Restrictions.isNull("name.genusOrUninomial"));
919
        } else if(!genusOrUninomial.equals("*")) {
920
            criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));
921
        }
922

    
923
        if(infraGenericEpithet == null) {
924
            criteria.add(Restrictions.isNull("name.infraGenericEpithet"));
925
        } else if(!infraGenericEpithet.equals("*")) {
926
            criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));
927
        }
928

    
929
        if(specificEpithet == null) {
930
            criteria.add(Restrictions.isNull("name.specificEpithet"));
931
        } else if(!specificEpithet.equals("*")) {
932
            criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));
933

    
934
        }
935

    
936
        if(infraSpecificEpithet == null) {
937
            criteria.add(Restrictions.isNull("name.infraSpecificEpithet"));
938
        } else if(!infraSpecificEpithet.equals("*")) {
939
            criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));
940
        }
941

    
942
        if(authorship == null) {
943
            criteria.add(Restrictions.eq("name.authorshipCache", ""));
944
        } else if(!authorship.equals("*")) {
945
            criteria.add(Restrictions.eq("name.authorshipCache", authorship));
946
        }
947

    
948
        if(rank != null) {
949
            criteria.add(Restrictions.eq("name.rank", rank));
950
        }
951

    
952
        if(pageSize != null) {
953
            criteria.setMaxResults(pageSize);
954
            if(pageNumber != null) {
955
                criteria.setFirstResult(pageNumber * pageSize);
956
            } else {
957
                criteria.setFirstResult(0);
958
            }
959
        }
960

    
961
        return criteria.list();
962
    }
963

    
964
    @Override
965
    public List<TaxonRelationship> getTaxonRelationships(Taxon taxon, TaxonRelationshipType type,
966
            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
967
            List<String> propertyPaths, Direction direction) {
968

    
969
        AuditEvent auditEvent = getAuditEventFromContext();
970
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
971

    
972
            Criteria criteria = getSession().createCriteria(TaxonRelationship.class);
973

    
974
            if(direction != null) {
975
                criteria.add(Restrictions.eq(direction.name(), taxon));
976
            } else {
977
                criteria.add(Restrictions.or(
978
                        Restrictions.eq(Direction.relatedFrom.name(), taxon),
979
                        Restrictions.eq(Direction.relatedTo.name(), taxon))
980
                    );
981
            }
982

    
983
            if(type != null) {
984
                criteria.add(Restrictions.eq("type", type));
985
            }
986

    
987
            addOrder(criteria,orderHints);
988

    
989
            if(pageSize != null) {
990
                criteria.setMaxResults(pageSize);
991
                if(pageNumber != null) {
992
                    criteria.setFirstResult(pageNumber * pageSize);
993
                } else {
994
                    criteria.setFirstResult(0);
995
                }
996
            }
997

    
998
            @SuppressWarnings("unchecked")
999
            List<TaxonRelationship> result = criteria.list();
1000
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1001

    
1002
            return result;
1003
        } else {
1004
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());
1005
            query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));
1006

    
1007
            if(type != null) {
1008
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1009
            }
1010

    
1011
            if(pageSize != null) {
1012
                query.setMaxResults(pageSize);
1013
                if(pageNumber != null) {
1014
                    query.setFirstResult(pageNumber * pageSize);
1015
                } else {
1016
                    query.setFirstResult(0);
1017
                }
1018
            }
1019

    
1020
            List<TaxonRelationship> result = query.getResultList();
1021
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1022

    
1023
            // Ugly, but for now, there is no way to sort on a related entity property in Envers,
1024
            // and we can't live without this functionality in CATE as it screws up the whole
1025
            // taxon tree thing
1026
            if(orderHints != null && !orderHints.isEmpty()) {
1027
                SortedSet<TaxonRelationship> sortedList = new TreeSet<TaxonRelationship>(new TaxonRelationshipFromTaxonComparator());
1028
                sortedList.addAll(result);
1029
                return new ArrayList<TaxonRelationship>(sortedList);
1030
            }
1031

    
1032
            return result;
1033
        }
1034
    }
1035

    
1036
    class TaxonRelationshipFromTaxonComparator implements Comparator<TaxonRelationship> {
1037

    
1038
        @Override
1039
        public int compare(TaxonRelationship o1, TaxonRelationship o2) {
1040
            if (o1.equals(o2)){
1041
                return 0;
1042
            }
1043
            int result = o1.getFromTaxon().getTitleCache().compareTo(o2.getFromTaxon().getTitleCache());
1044
            if (result == 0 ){
1045
                result = o1.getUuid().compareTo(o2.getUuid());
1046
            }
1047
            return result;
1048
        }
1049

    
1050
    }
1051

    
1052
    @Override
1053
    public List<Synonym> getSynonyms(Taxon taxon, SynonymType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
1054
        AuditEvent auditEvent = getAuditEventFromContext();
1055
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1056
            Criteria criteria = getSession().createCriteria(Synonym.class);
1057

    
1058
            criteria.add(Restrictions.eq("acceptedTaxon", taxon));
1059
            if(type != null) {
1060
                criteria.add(Restrictions.eq("type", type));
1061
            }
1062

    
1063
            addOrder(criteria,orderHints);
1064

    
1065
            if(pageSize != null) {
1066
                criteria.setMaxResults(pageSize);
1067
                if(pageNumber != null) {
1068
                    criteria.setFirstResult(pageNumber * pageSize);
1069
                } else {
1070
                    criteria.setFirstResult(0);
1071
                }
1072
            }
1073

    
1074
            @SuppressWarnings("unchecked")
1075
            List<Synonym> result = criteria.list();
1076
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1077

    
1078
            return result;
1079
        } else {
1080
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(Synonym.class,auditEvent.getRevisionNumber());
1081
            query.add(AuditEntity.relatedId("acceptedTaxon").eq(taxon.getId()));
1082

    
1083
            if(type != null) {
1084
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1085
            }
1086

    
1087
            if(pageSize != null) {
1088
                query.setMaxResults(pageSize);
1089
                if(pageNumber != null) {
1090
                    query.setFirstResult(pageNumber * pageSize);
1091
                } else {
1092
                    query.setFirstResult(0);
1093
                }
1094
            }
1095

    
1096
            List<Synonym> result = query.getResultList();
1097
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1098

    
1099
            return result;
1100
        }
1101
    }
1102

    
1103
    @Override
1104
    public void rebuildIndex() {
1105
        FullTextSession fullTextSession = Search.getFullTextSession(getSession());
1106

    
1107
        for(TaxonBase taxonBase : list(null,null)) { // re-index all taxon base
1108
            Hibernate.initialize(taxonBase.getName());
1109
            fullTextSession.index(taxonBase);
1110
        }
1111
        fullTextSession.flushToIndexes();
1112
    }
1113

    
1114
    @Override
1115
    public String suggestQuery(String queryString) {
1116
        throw new RuntimeException("Query suggestion currently not implemented in TaxonDaoHibernateImpl");
1117
//        checkNotInPriorView("TaxonDaoHibernateImpl.suggestQuery(String queryString)");
1118
//        String alternativeQueryString = null;
1119
//        if (alternativeSpellingSuggestionParser != null) {
1120
//            try {
1121
//
1122
//                alternativeSpellingSuggestionParser.parse(queryString);
1123
//                org.apache.lucene.search.Query alternativeQuery = alternativeSpellingSuggestionParser.suggest(queryString);
1124
//                if (alternativeQuery != null) {
1125
//                    alternativeQueryString = alternativeQuery
1126
//                            .toString("name.titleCache");
1127
//                }
1128
//
1129
//            } catch (ParseException e) {
1130
//                throw new QueryParseException(e, queryString);
1131
//            }
1132
//        }
1133
//        return alternativeQueryString;
1134
    }
1135

    
1136
    @Override
1137
    public Taxon acceptedTaxonFor(Synonym synonym, Classification classificationFilter, List<String> propertyPaths){
1138

    
1139
        String hql = prepareListAcceptedTaxaFor(classificationFilter, false);
1140

    
1141
        Query query = getSession().createQuery(hql);
1142

    
1143
        query.setParameter("synonym", synonym);
1144

    
1145
        if(classificationFilter != null){
1146
            query.setParameter("classificationFilter", classificationFilter);
1147
        }
1148

    
1149
        @SuppressWarnings("unchecked")
1150
        List<Taxon> result = query.list();
1151

    
1152
        defaultBeanInitializer.initializeAll(result, propertyPaths);
1153

    
1154
        return result.isEmpty()? null: result.get(0);
1155
    }
1156

    
1157
    @Override
1158
    public long countAcceptedTaxonFor(Synonym synonym, Classification classificationFilter){
1159

    
1160
        String hql = prepareListAcceptedTaxaFor(classificationFilter, true);
1161

    
1162
        Query query = getSession().createQuery(hql);
1163

    
1164
        query.setParameter("synonym", synonym);
1165

    
1166
        if(classificationFilter != null){
1167
            query.setParameter("classificationFilter", classificationFilter);
1168
        }
1169

    
1170
        Long count = Long.parseLong(query.uniqueResult().toString());
1171

    
1172
        return count;
1173

    
1174
    }
1175

    
1176

    
1177
    /**
1178
     * @param classificationFilter
1179
     * @param orderHints
1180
     * @return
1181
     */
1182
    private String prepareListAcceptedTaxaFor(Classification classificationFilter, boolean doCount) {
1183

    
1184
        String hql;
1185
        String hqlSelect = "SELECT " + (doCount? "COUNT(taxon)" : "taxon") + " FROM Synonym as syn JOIN syn.acceptedTaxon as taxon ";
1186
        String hqlWhere = " WHERE syn = :synonym";
1187

    
1188
        if(classificationFilter != null){
1189
            hqlSelect += " JOIN taxon.taxonNodes AS taxonNode";
1190
            hqlWhere += " AND taxonNode.classification = :classificationFilter";
1191
        }
1192
        hql = hqlSelect + hqlWhere;
1193
        return hql;
1194
    }
1195

    
1196
    @Override
1197
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, Integer limit, String pattern) {
1198
        int classificationId = classification.getId();
1199
        // StringBuffer excludeUuids = new StringBuffer();
1200

    
1201
         String queryString = "SELECT nodes.uuid, nodes.id, taxon.titleCache FROM TaxonNode AS nodes JOIN nodes.taxon as taxon WHERE nodes.classification.id = " + classificationId ;
1202
         if (pattern != null){
1203
             if (pattern.equals("?")){
1204
                 limit = null;
1205
             } else{
1206
                 if (!pattern.endsWith("*")){
1207
                     pattern += "%";
1208
                 }
1209
                 pattern = pattern.replace("*", "%");
1210
                 pattern = pattern.replace("?", "%");
1211
                 queryString = queryString + " AND taxon.titleCache like (:pattern)" ;
1212
             }
1213
         }
1214

    
1215

    
1216

    
1217
         Query query = getSession().createQuery(queryString);
1218

    
1219

    
1220
         if (limit != null){
1221
             query.setMaxResults(limit);
1222
         }
1223

    
1224
         if (pattern != null && !pattern.equals("?")){
1225
             query.setParameter("pattern", pattern);
1226
         }
1227
         @SuppressWarnings("unchecked")
1228
         List<Object[]> result = query.list();
1229

    
1230
         if(result.size() == 0){
1231
             return null;
1232
         }else{
1233
             List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<UuidAndTitleCache<TaxonNode>>(result.size());
1234

    
1235
             for (Object object : result){
1236

    
1237
                 Object[] objectArray = (Object[]) object;
1238

    
1239
                 UUID uuid = (UUID)objectArray[0];
1240
                 Integer id = (Integer) objectArray[1];
1241
                 String titleCache = (String) objectArray[2];
1242

    
1243
                 list.add(new UuidAndTitleCache<TaxonNode>(TaxonNode.class, uuid, id, titleCache));
1244
             }
1245

    
1246
             return list;
1247
         }
1248
    }
1249

    
1250

    
1251
    @Override
1252
    public TaxonBase find(LSID lsid) {
1253
        TaxonBase<?> taxonBase = super.find(lsid);
1254
        if(taxonBase != null) {
1255
            List<String> propertyPaths = new ArrayList<String>();
1256
            propertyPaths.add("createdBy");
1257
            propertyPaths.add("updatedBy");
1258
            propertyPaths.add("name");
1259
            propertyPaths.add("sec");
1260
            propertyPaths.add("relationsToThisTaxon");
1261
            propertyPaths.add("relationsToThisTaxon.fromTaxon");
1262
            propertyPaths.add("relationsToThisTaxon.toTaxon");
1263
            propertyPaths.add("relationsFromThisTaxon");
1264
            propertyPaths.add("relationsFromThisTaxon.toTaxon");
1265
            propertyPaths.add("relationsToThisTaxon.type");
1266
            propertyPaths.add("synonyms");
1267
            propertyPaths.add("synonyms.type");
1268
            propertyPaths.add("descriptions");
1269

    
1270
            defaultBeanInitializer.initialize(taxonBase, propertyPaths);
1271
        }
1272
        return taxonBase;
1273
    }
1274

    
1275

    
1276

    
1277
    @Override
1278
    public List<String> taxaByNameNotInDB(List<String> taxonNames){
1279
        //get all taxa, already in db
1280
        Query query = getSession().createQuery("from TaxonName t where t.nameCache IN (:taxonList)");
1281
        query.setParameterList("taxonList", taxonNames);
1282
        List<TaxonName> taxaInDB = query.list();
1283
        //compare the original list with the result of the query
1284
        for (TaxonName taxonName: taxaInDB){
1285
            String nameCache = taxonName.getNameCache();
1286
            if (taxonNames.contains(nameCache)){
1287
                taxonNames.remove(nameCache);
1288
            }
1289

    
1290
        }
1291

    
1292
        return taxonNames;
1293
    }
1294

    
1295
    //TODO: mal nur mit UUID probieren (ohne fetch all properties), vielleicht geht das schneller?
1296
    @Override
1297
    public List<UUID> findIdenticalTaxonNameIds(List<String> propertyPaths){
1298
        Query query=getSession().createQuery("select tmb2 from ZoologicalName tmb, ZoologicalName tmb2 fetch all properties where tmb.id != tmb2.id and tmb.nameCache = tmb2.nameCache");
1299
        List<UUID> zooNames = query.list();
1300

    
1301
        return zooNames;
1302

    
1303
    }
1304

    
1305
    @Override
1306
    public List<TaxonName> findIdenticalTaxonNames(List<String> propertyPaths) {
1307

    
1308
        Query query=getSession().createQuery("select tmb2 from ZoologicalName tmb, ZoologicalName tmb2 fetch all properties where tmb.id != tmb2.id and tmb.nameCache = tmb2.nameCache");
1309

    
1310
        @SuppressWarnings("unchecked")
1311
        List<TaxonName> zooNames = query.list();
1312

    
1313
        TaxonNameComparator taxComp = new TaxonNameComparator();
1314
        Collections.sort(zooNames, taxComp);
1315

    
1316
        for (TaxonName taxonName: zooNames){
1317
            defaultBeanInitializer.initialize(taxonName, propertyPaths);
1318
        }
1319

    
1320
        return zooNames;
1321
    }
1322

    
1323
    @Override
1324
    public List<TaxonName> findIdenticalNamesNew(List<String> propertyPaths){
1325

    
1326
        //Hole die beiden Source_ids von "Fauna Europaea" und "Erms" und in sources der names darf jeweils nur das entgegengesetzte auftreten (i member of tmb.taxonBases)
1327
        Query query = getSession().createQuery("Select id from Reference where titleCache like 'Fauna Europaea database'");
1328
        List<String> secRefFauna = query.list();
1329
        query = getSession().createQuery("Select id from Reference where titleCache like 'ERMS'");
1330
        List<String> secRefErms = query.list();
1331
        //Query query = getSession().createQuery("select tmb2.nameCache from ZoologicalName tmb, TaxonBase tb1, ZoologicalName tmb2, TaxonBase tb2 where tmb.id != tmb2.id and tb1.name = tmb and tb2.name = tmb2 and tmb.nameCache = tmb2.nameCache and tb1.sec != tb2.sec");
1332
        //Get all names of fauna europaea
1333
        query = getSession().createQuery("select zn.nameCache from ZoologicalName zn, TaxonBase tb where tb.name = zn and tb.sec.id = :secRefFauna");
1334
        query.setParameter("secRefFauna", secRefFauna.get(0));
1335
        List<String> namesFauna= query.list();
1336

    
1337
        //Get all names of erms
1338

    
1339
        query = getSession().createQuery("select zn.nameCache from ZoologicalName zn, TaxonBase tb where tb.name = zn and tb.sec.id = :secRefErms");
1340
        query.setParameter("secRefErms", secRefErms.get(0));
1341

    
1342
        List<String> namesErms = query.list();
1343
        /*TaxonNameComparator comp = new TaxonNameComparator();
1344
        Collections.sort(namesFauna);
1345
        Collections.sort(namesErms);
1346
        */
1347
        List <String> identicalNames = new ArrayList<String>();
1348
        String predecessor = "";
1349

    
1350
        for (String nameFauna: namesFauna){
1351
            if (namesErms.contains(nameFauna)){
1352
                identicalNames.add(nameFauna);
1353
            }
1354
        }
1355

    
1356

    
1357
        query = getSession().createQuery("from ZoologicalName zn where zn.nameCache IN (:identicalNames)");
1358
        query.setParameterList("identicalNames", identicalNames);
1359
        List<TaxonName> result = query.list();
1360
        TaxonName temp = result.get(0);
1361

    
1362
        Iterator<OriginalSourceBase> sources = temp.getSources().iterator();
1363

    
1364
        TaxonNameComparator taxComp = new TaxonNameComparator();
1365
        Collections.sort(result, taxComp);
1366
        defaultBeanInitializer.initializeAll(result, propertyPaths);
1367
        return result;
1368

    
1369
    }
1370

    
1371
//
1372
//
1373
//    @Override
1374
//    public String getPhylumName(TaxonName name){
1375
//        List results = new ArrayList();
1376
//        try{
1377
//        Query query = getSession().createSQLQuery("select getPhylum("+ name.getId()+");");
1378
//        results = query.list();
1379
//        }catch(Exception e){
1380
//            System.err.println(name.getUuid());
1381
//            return null;
1382
//        }
1383
//        System.err.println("phylum of "+ name.getTitleCache() );
1384
//        return (String)results.get(0);
1385
//    }
1386

    
1387

    
1388
    @Override
1389
    public long countTaxaByCommonName(String searchString,
1390
            Classification classification, MatchMode matchMode,
1391
            Set<NamedArea> namedAreas) {
1392
        boolean doCount = true;
1393
        Query query = prepareTaxaByCommonName(searchString, classification, matchMode, namedAreas, null, null, doCount, false);
1394
        if (query != null && !query.list().isEmpty()) {
1395
            Object o = query.uniqueResult();
1396
            if(o != null) {
1397
                return (Long)o;
1398
            }
1399
        }
1400
        return 0;
1401
    }
1402

    
1403
    private String[] createHQLString(boolean doTaxa, boolean doSynonyms, boolean doIncludeMisappliedNames, Classification classification,  Set<NamedArea> areasExpanded, MatchMode matchMode, String searchField){
1404

    
1405
           boolean doAreaRestriction = areasExpanded.size() > 0;
1406
           String 	doAreaRestrictionSubSelect = "select %s.id from" +
1407
                " Distribution e" +
1408
                " join e.inDescription d" +
1409
                " join d.taxon t" +
1410
                (classification != null ? " join t.taxonNodes as tn " : " ");
1411

    
1412
           String 	doAreaRestrictionMisappliedNameSubSelect = "select %s.id from" +
1413
            " Distribution e" +
1414
            " join e.inDescription d" +
1415
            " join d.taxon t";
1416

    
1417
           String doTaxonSubSelect = "select %s.id from Taxon t " + (classification != null ? " join t.taxonNodes as tn " : " ");
1418
           String doTaxonMisappliedNameSubSelect = "select %s.id from Taxon t ";
1419

    
1420
           String doTaxonNameJoin =   " join t.name n ";
1421

    
1422
           String doSynonymNameJoin =  	" join t.synonyms s join s.name sn";
1423

    
1424
           String doMisappliedNamesJoin = " left join t.relationsFromThisTaxon as rft" +
1425
                " left join rft.relatedTo as rt" +
1426
                (classification != null ? " left join rt.taxonNodes as tn2" : " ") +
1427
                " left join rt.name as n2" +
1428
                " left join rft.type as rtype";
1429

    
1430
           String doCommonNamesJoin =   "join t.descriptions as description "+
1431
                   "left join description.descriptionElements as com " +
1432
                   "left join com.feature f ";
1433

    
1434

    
1435
           String doClassificationWhere = " tn.classification = :classification";
1436
           String doClassificationForMisappliedNamesWhere = " tn2 .classification = :classification";
1437

    
1438
           String doAreaRestrictionWhere =  " e.area.uuid in (:namedAreasUuids)";
1439
           String doCommonNamesRestrictionWhere = " (f.supportsCommonTaxonName = true and com.name "+matchMode.getMatchOperator()+" :queryString )";
1440

    
1441
           String doSearchFieldWhere = "%s." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
1442

    
1443
           String doRelationshipTypeComparison = " rtype = :rType ";
1444

    
1445
        String taxonSubselect = null;
1446
        String synonymSubselect = null;
1447
        String misappliedSelect = null;
1448
        String commonNameSubselect = null;
1449

    
1450
        if(classification != null ){
1451
            if (!doIncludeMisappliedNames){
1452
                if(doAreaRestriction){
1453
                    taxonSubselect = String.format(doAreaRestrictionSubSelect, "t") + doTaxonNameJoin +
1454
                    " WHERE " + doAreaRestrictionWhere +
1455
                    " AND " + doClassificationWhere +
1456
                    " AND " + String.format(doSearchFieldWhere, "n");
1457
                    synonymSubselect = String.format(doAreaRestrictionSubSelect, "s") + doSynonymNameJoin +
1458
                    " WHERE " + doAreaRestrictionWhere +
1459
                    " AND " + doClassificationWhere +
1460
                    " AND " + String.format(doSearchFieldWhere, "sn");
1461
                    commonNameSubselect =  String.format(doAreaRestrictionSubSelect, "t") + doCommonNamesJoin +
1462
                            " WHERE " +  doAreaRestrictionWhere + " AND " + doClassificationWhere +
1463
                            " AND " + String.format(doSearchFieldWhere, "n")
1464
                            + " AND " + doCommonNamesRestrictionWhere;
1465
                } else {
1466
                    taxonSubselect = String.format(doTaxonSubSelect, "t" )+ doTaxonNameJoin +
1467
                    " WHERE " + doClassificationWhere +
1468
                    " AND " + String.format(doSearchFieldWhere, "n");
1469
                    synonymSubselect = String.format(doTaxonSubSelect, "s" ) + doSynonymNameJoin +
1470
                    " WHERE " + doClassificationWhere +
1471
                    " AND " + String.format(doSearchFieldWhere, "sn");
1472
                    commonNameSubselect =String.format(doTaxonSubSelect, "t" )+ doCommonNamesJoin +
1473
                            " WHERE " + doClassificationWhere +
1474
                            " AND " + doCommonNamesRestrictionWhere;
1475
                }
1476
            }else{ //misappliedNames included
1477
                if(doAreaRestriction){
1478
                    misappliedSelect = String.format(doAreaRestrictionMisappliedNameSubSelect, "t") + doTaxonNameJoin + doMisappliedNamesJoin  +
1479
                    " WHERE " + doAreaRestrictionWhere +
1480
                    " AND " + String.format(doSearchFieldWhere, "n") +
1481
                    " AND " + doClassificationForMisappliedNamesWhere +
1482
                    " AND " + doRelationshipTypeComparison;
1483

    
1484
                    taxonSubselect = String.format(doAreaRestrictionSubSelect, "t") + doTaxonNameJoin +
1485
                    " WHERE " + doAreaRestrictionWhere +
1486
                    " AND "+ String.format(doSearchFieldWhere, "n") + " AND "+ doClassificationWhere;
1487

    
1488
                    synonymSubselect = String.format(doAreaRestrictionSubSelect, "s") + doSynonymNameJoin +
1489
                    " WHERE " + doAreaRestrictionWhere +
1490
                    " AND " + doClassificationWhere + " AND " +  String.format(doSearchFieldWhere, "sn");
1491

    
1492
                    commonNameSubselect= String.format(doAreaRestrictionSubSelect, "t")+ doCommonNamesJoin +
1493
                            " WHERE " + doAreaRestrictionWhere +
1494
                            " AND "+ doClassificationWhere + " AND " + doCommonNamesRestrictionWhere;
1495
                } else {
1496
                    misappliedSelect = String.format(doTaxonMisappliedNameSubSelect, "t" ) + doTaxonNameJoin + doMisappliedNamesJoin +
1497
                    " WHERE " + String.format(doSearchFieldWhere, "n") +
1498
                    " AND " + doClassificationForMisappliedNamesWhere +
1499
                    " AND " + doRelationshipTypeComparison;
1500

    
1501
                    taxonSubselect = String.format(doTaxonSubSelect, "t" ) + doTaxonNameJoin +
1502
                    " WHERE " +  String.format(doSearchFieldWhere, "n") +
1503
                    " AND "+ doClassificationWhere;
1504

    
1505
                    synonymSubselect = String.format(doTaxonSubSelect, "s" ) + doSynonymNameJoin +
1506
                    " WHERE " + doClassificationWhere +
1507
                    " AND " +  String.format(doSearchFieldWhere, "sn");
1508

    
1509
                    commonNameSubselect= String.format(doTaxonSubSelect, "t")+ doCommonNamesJoin +
1510
                            " WHERE " + doClassificationWhere + " AND " + doCommonNamesRestrictionWhere;
1511

    
1512
                }
1513
            }
1514
        } else {
1515
            if(doAreaRestriction){
1516
                misappliedSelect = String.format(doAreaRestrictionMisappliedNameSubSelect, "t") + doTaxonNameJoin + doMisappliedNamesJoin +
1517
                " WHERE " + doAreaRestrictionWhere +
1518
                " AND " + String.format(doSearchFieldWhere, "n")+
1519
                " AND " + doRelationshipTypeComparison;
1520

    
1521
                taxonSubselect = String.format(doAreaRestrictionSubSelect, "t") + doTaxonNameJoin +
1522
                " WHERE " + doAreaRestrictionWhere +
1523
                " AND " + String.format(doSearchFieldWhere, "n");
1524

    
1525
                synonymSubselect = String.format(doAreaRestrictionSubSelect, "s") + doSynonymNameJoin +
1526
                " WHERE " +   doAreaRestrictionWhere +
1527
                " AND " +  String.format(doSearchFieldWhere, "sn");
1528
                commonNameSubselect = String.format(doAreaRestrictionSubSelect, "t")+ doCommonNamesJoin +
1529
                        " WHERE " + doAreaRestrictionWhere +
1530
                        " AND " + doCommonNamesRestrictionWhere;
1531

    
1532

    
1533
            } else {
1534
                misappliedSelect = String.format(doTaxonMisappliedNameSubSelect, "t" ) + doTaxonNameJoin + doMisappliedNamesJoin + " WHERE " +  String.format(doSearchFieldWhere, "n") + " AND " + doRelationshipTypeComparison;
1535
                taxonSubselect = String.format(doTaxonSubSelect, "t" ) + doTaxonNameJoin + " WHERE " +  String.format(doSearchFieldWhere, "n");
1536
                synonymSubselect = String.format(doTaxonSubSelect, "s" ) + doSynonymNameJoin + " WHERE " +  String.format(doSearchFieldWhere, "sn");
1537
                commonNameSubselect = String.format(doTaxonSubSelect, "t" ) +doCommonNamesJoin + " WHERE "+  doCommonNamesRestrictionWhere;
1538

    
1539
            }
1540
        }
1541
        String[] result = {misappliedSelect, taxonSubselect, synonymSubselect, commonNameSubselect};
1542

    
1543
        return result;
1544
    }
1545

    
1546
	@Override
1547
	public List<UuidAndTitleCache<IdentifiableEntity>> getTaxaByCommonNameForEditor(
1548
			String titleSearchStringSqlized, Classification classification,
1549
			MatchMode matchMode, Set namedAreas) {
1550
	    List<Object> resultArray = new ArrayList<Object>();
1551
		Query query = prepareTaxaByCommonName(titleSearchStringSqlized, classification, matchMode, namedAreas, null, null, false, true);
1552
        if (query != null){
1553
            resultArray = query.list();
1554
            List<UuidAndTitleCache<IdentifiableEntity>> returnResult = new ArrayList<UuidAndTitleCache<IdentifiableEntity>>() ;
1555
            Object[] result;
1556
            for(int i = 0; i<resultArray.size();i++){
1557
            	result = (Object[]) resultArray.get(i);
1558
            	returnResult.add(new UuidAndTitleCache(Taxon.class, (UUID) result[0],(Integer)result[1], (String)result[2], new Boolean(result[4].toString()), null));
1559
            }
1560
            return returnResult;
1561
        }
1562

    
1563
		return null;
1564
	}
1565

    
1566

    
1567
	/**
1568
	 * @param
1569
	 * @see eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao#countByIdentifier(java.lang.Class, java.lang.String, eu.etaxonomy.cdm.model.common.DefinedTerm, eu.etaxonomy.cdm.model.taxon.TaxonNode, eu.etaxonomy.cdm.persistence.query.MatchMode)
1570
	 */
1571
	@Override
1572
	public <S extends TaxonBase> int countByIdentifier(Class<S> clazz,
1573
			String identifier, DefinedTerm identifierType, TaxonNode subtreeFilter, MatchMode matchmode) {
1574
		if (subtreeFilter == null){
1575
			return countByIdentifier(clazz, identifier, identifierType, matchmode);
1576
		}
1577

    
1578
		Class<?> clazzParam = clazz == null ? type : clazz;
1579
		checkNotInPriorView("TaxonDaoHibernateImpl.countByIdentifier(T clazz, String identifier, DefinedTerm identifierType, TaxonNode subMatchMode matchmode)");
1580

    
1581
		boolean isTaxon = clazzParam == Taxon.class || clazzParam == TaxonBase.class;
1582
		boolean isSynonym = clazzParam == Synonym.class || clazzParam == TaxonBase.class;
1583

    
1584
		getSession().update(subtreeFilter);  //to avoid LIE when retrieving treeindex
1585
		String filterStr = "'" + subtreeFilter.treeIndex() + "%%'";
1586
		String accTreeJoin = isTaxon? " LEFT JOIN c.taxonNodes tn  " : "";
1587
		String synTreeJoin = isSynonym ? " LEFT JOIN c.acceptedTaxon as acc LEFT JOIN acc.taxonNodes synTn  " : "";
1588
		String accWhere = isTaxon ?  "tn.treeIndex like " + filterStr : "(1=0)";
1589
		String synWhere = isSynonym  ?  "synTn.treeIndex like " + filterStr : "(1=0)";
1590

    
1591
		String queryString = "SELECT count(*)  FROM %s as c " +
1592
                " INNER JOIN c.identifiers as ids " +
1593
                accTreeJoin +
1594
                synTreeJoin +
1595
                " WHERE (1=1) " +
1596
                	"  AND ( " + accWhere + " OR " + synWhere + ")";
1597
		queryString = String.format(queryString, clazzParam.getSimpleName());
1598

    
1599
		if (identifier != null){
1600
			if (matchmode == null || matchmode == MatchMode.EXACT){
1601
				queryString += " AND ids.identifier = '"  + identifier + "'";
1602
			}else {
1603
				queryString += " AND ids.identifier LIKE '" + matchmode.queryStringFrom(identifier)  + "'";
1604
			}
1605
		}
1606
		if (identifierType != null){
1607
        	queryString += " AND ids.type = :type";
1608
        }
1609

    
1610
		Query query = getSession().createQuery(queryString);
1611
        if (identifierType != null){
1612
        	query.setEntity("type", identifierType);
1613
        }
1614

    
1615
		Long c = (Long)query.uniqueResult();
1616
        return c.intValue();
1617
	}
1618

    
1619
	@Override
1620
	public <S extends TaxonBase> List<Object[]> findByIdentifier(
1621
			Class<S> clazz, String identifier, DefinedTerm identifierType, TaxonNode subtreeFilter,
1622
			MatchMode matchmode, boolean includeEntity,
1623
			Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
1624

    
1625
		checkNotInPriorView("TaxonDaoHibernateImpl.findByIdentifier(T clazz, String identifier, DefinedTerm identifierType, MatchMode matchmode, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths)");
1626
		Class<?> clazzParam = clazz == null ? type : clazz;
1627

    
1628
		boolean isTaxon = clazzParam == Taxon.class || clazzParam == TaxonBase.class;
1629
		boolean isSynonym = clazzParam == Synonym.class || clazzParam == TaxonBase.class;
1630
		getSession().update(subtreeFilter);  //to avoid LIE when retrieving treeindex
1631
		String filterStr = "'" + subtreeFilter.treeIndex() + "%%'";
1632
		String accTreeJoin = isTaxon? " LEFT JOIN c.taxonNodes tn  " : "";
1633
		String synTreeJoin = isSynonym ? " LEFT JOIN c.acceptedTaxon as acc LEFT JOIN acc.taxonNodes synTn  " : "";
1634
		String accWhere = isTaxon ?  "tn.treeIndex like " + filterStr : "(1=0)";
1635
		String synWhere = isSynonym  ?  "synTn.treeIndex like " + filterStr : "(1=0)";
1636

    
1637
		String queryString = "SELECT ids.type, ids.identifier, %s " +
1638
				" FROM %s as c " +
1639
                " INNER JOIN c.identifiers as ids " +
1640
                accTreeJoin +
1641
				synTreeJoin +
1642
                " WHERE (1=1) " +
1643
                	" AND ( " + accWhere + " OR " + synWhere + ")";
1644
		queryString = String.format(queryString, (includeEntity ? "c":"c.uuid, c.titleCache") , clazzParam.getSimpleName());
1645

    
1646
		//Matchmode and identifier
1647
		if (identifier != null){
1648
			if (matchmode == null || matchmode == MatchMode.EXACT){
1649
				queryString += " AND ids.identifier = '"  + identifier + "'";
1650
			}else {
1651
				queryString += " AND ids.identifier LIKE '" + matchmode.queryStringFrom(identifier)  + "'";
1652
			}
1653
		}
1654
        if (identifierType != null){
1655
        	queryString += " AND ids.type = :type";
1656
        }
1657
        //order
1658
        queryString +=" ORDER BY ids.type.uuid, ids.identifier, c.uuid ";
1659

    
1660
		Query query = getSession().createQuery(queryString);
1661

    
1662
		//parameters
1663
		if (identifierType != null){
1664
        	query.setEntity("type", identifierType);
1665
        }
1666

    
1667
        //paging
1668
        setPagingParameter(query, pageSize, pageNumber);
1669

    
1670
        List<Object[]> results = query.list();
1671
        //initialize
1672
        if (includeEntity){
1673
        	List<S> entities = new ArrayList<S>();
1674
        	for (Object[] result : results){
1675
        		entities.add((S)result[2]);
1676
        	}
1677
        	defaultBeanInitializer.initializeAll(entities, propertyPaths);
1678
        }
1679
        return results;
1680
	}
1681

    
1682
    /**
1683
     * {@inheritDoc}
1684
     * @see #countByIdentifier(Class, String, DefinedTerm, TaxonNode, MatchMode)
1685
     */
1686
    @Override
1687
    public <S extends TaxonBase> long countByMarker(Class<S> clazz, MarkerType markerType,
1688
            Boolean markerValue, TaxonNode subtreeFilter) {
1689
        if (markerType == null){
1690
            return 0;
1691
        }
1692

    
1693
        if (subtreeFilter == null){
1694
            return countByMarker(clazz, markerType, markerValue);
1695
        }
1696

    
1697
        Class<?> clazzParam = clazz == null ? type : clazz;
1698
        checkNotInPriorView("TaxonDaoHibernateImpl.countByMarker(Class<S> clazz, DefinedTerm markerType, boolean markerValue, TaxonNode subtreeFilter)");
1699

    
1700
        boolean isTaxon = clazzParam == Taxon.class || clazzParam == TaxonBase.class;
1701
        boolean isSynonym = clazzParam == Synonym.class || clazzParam == TaxonBase.class;
1702

    
1703
        getSession().update(subtreeFilter);  //to avoid LIE when retrieving treeindex
1704
        String filterStr = "'" + subtreeFilter.treeIndex() + "%%'";
1705
        String accTreeJoin = isTaxon? " LEFT JOIN c.taxonNodes tn  " : "";
1706
        String synTreeJoin = isSynonym ? " LEFT JOIN c.acceptedTaxon acc LEFT JOIN acc.taxonNodes synTn  " : "";
1707
        String accWhere = isTaxon ?  "tn.treeIndex like " + filterStr : "(1=0)";
1708
        String synWhere = isSynonym  ?  "synTn.treeIndex like " + filterStr : "(1=0)";
1709

    
1710
        String queryString = "SELECT count(*)  FROM %s as c " +
1711
                " INNER JOIN c.markers as mks " +
1712
                accTreeJoin +
1713
                synTreeJoin +
1714
                " WHERE (1=1) " +
1715
                    "  AND ( " + accWhere + " OR " + synWhere + ")";
1716
        queryString = String.format(queryString, clazzParam.getSimpleName());
1717

    
1718
        if (markerValue != null){
1719
            queryString += " AND mks.flag = :flag";
1720
        }
1721
        if (markerType != null){
1722
            queryString += " AND mks.markerType = :type";
1723
        }
1724

    
1725
        Query query = getSession().createQuery(queryString);
1726
        if (markerType != null){
1727
            query.setEntity("type", markerType);
1728
        }
1729
        if (markerValue != null){
1730
            query.setBoolean("flag", markerValue);
1731
        }
1732

    
1733
        Long c = (Long)query.uniqueResult();
1734
        return c;
1735
    }
1736

    
1737
    /**
1738
     * {@inheritDoc}
1739
     */
1740
    @Override
1741
    public <S extends TaxonBase> List<Object[]> findByMarker(Class<S> clazz, MarkerType markerType,
1742
            Boolean markerValue, TaxonNode subtreeFilter, boolean includeEntity,
1743
            TaxonTitleType titleType, Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
1744
        checkNotInPriorView("TaxonDaoHibernateImpl.findByMarker(T clazz, String identifier, DefinedTerm identifierType, MatchMode matchmode, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths)");
1745
        if (markerType == null){
1746
            return new ArrayList<Object[]>();
1747
        }
1748
        if (titleType == null){
1749
            titleType = TaxonTitleType.DEFAULT();
1750
        }
1751

    
1752
        Class<?> clazzParam = clazz == null ? type : clazz;
1753

    
1754
        boolean isTaxon = clazzParam == Taxon.class || clazzParam == TaxonBase.class;
1755
        boolean isSynonym = clazzParam == Synonym.class || clazzParam == TaxonBase.class;
1756
        getSession().update(subtreeFilter);  //to avoid LIE when retrieving treeindex
1757
        String filterStr = "'" + subtreeFilter.treeIndex() + "%%'";
1758
        String accTreeJoin = isTaxon? " LEFT JOIN c.taxonNodes tn  " : "";
1759
        String synTreeJoin = isSynonym ? " LEFT JOIN c.acceptedTaxon as acc LEFT JOIN acc.taxonNodes synTn  " : "";
1760
        String accWhere = isTaxon ?  "tn.treeIndex like " + filterStr : "(1=0)";
1761
        String synWhere = isSynonym  ?  "synTn.treeIndex like " + filterStr : "(1=0)";
1762
        String selectParams = includeEntity ? "c" : titleType.hqlReplaceSelect("c.uuid, c.titleCache", "c.titleCache");
1763
        String titleTypeJoin = includeEntity ? "" : titleType.hqlJoin();
1764

    
1765
        String queryString = "SELECT mks.markerType, mks.flag, %s " +
1766
                " FROM %s as c " +
1767
                " INNER JOIN c.markers as mks " +
1768
                titleTypeJoin +
1769
                accTreeJoin +
1770
                synTreeJoin +
1771
                " WHERE (1=1) " +
1772
                    " AND ( " + accWhere + " OR " + synWhere + ")";
1773
        queryString = String.format(queryString, selectParams, clazzParam.getSimpleName());
1774

    
1775
        //type and value
1776
        if (markerValue != null){
1777
            queryString += " AND mks.flag = :flag";
1778
        }
1779
        queryString += " AND mks.markerType = :type";
1780
        //order
1781
        queryString +=" ORDER BY mks.markerType.uuid, mks.flag, c.uuid ";
1782

    
1783
        Query query = getSession().createQuery(queryString);
1784

    
1785
        //parameters
1786
        query.setEntity("type", markerType);
1787
        if (markerValue != null){
1788
            query.setBoolean("flag", markerValue);
1789
        }
1790

    
1791
        //paging
1792
        setPagingParameter(query, pageSize, pageNumber);
1793

    
1794
        List<Object[]> results = query.list();
1795
        //initialize
1796
        if (includeEntity){
1797
            List<S> entities = new ArrayList<S>();
1798
            for (Object[] result : results){
1799
                entities.add((S)result[2]);
1800
            }
1801
            defaultBeanInitializer.initializeAll(entities, propertyPaths);
1802
        }
1803
        return results;
1804
    }
1805

    
1806
    @Override
1807
    public long countTaxonRelationships(Set<TaxonRelationshipType> types) {
1808
        Criteria criteria = getSession().createCriteria(TaxonRelationship.class);
1809

    
1810
        if (types != null) {
1811
            if (types.isEmpty()){
1812
                return 0l;
1813
            }else{
1814
                criteria.add(Restrictions.in("type", types) );
1815
            }
1816
        }
1817
        //count
1818
        criteria.setProjection(Projections.rowCount());
1819
        long result = ((Number)criteria.uniqueResult()).longValue();
1820

    
1821
        return result;
1822
    }
1823

    
1824
    @Override
1825
    public List<TaxonRelationship> getTaxonRelationships(Set<TaxonRelationshipType> types,
1826
            Integer pageSize, Integer pageNumber,
1827
            List<OrderHint> orderHints, List<String> propertyPaths) {
1828
        Criteria criteria = getSession().createCriteria(TaxonRelationship.class);
1829

    
1830
        if (types != null) {
1831
            if (types.isEmpty()){
1832
                return new ArrayList<>();
1833
            }else{
1834
                criteria.add(Restrictions.in("type", types) );
1835
            }
1836
        }
1837
        addOrder(criteria,orderHints);
1838

    
1839
        if(pageSize != null) {
1840
            criteria.setMaxResults(pageSize);
1841
            if(pageNumber != null) {
1842
                criteria.setFirstResult(pageNumber * pageSize);
1843
            } else {
1844
                criteria.setFirstResult(0);
1845
            }
1846
        }
1847

    
1848
        List<TaxonRelationship> results = criteria.list();
1849
        defaultBeanInitializer.initializeAll(results, propertyPaths);
1850

    
1851
        return results;
1852
    }
1853

    
1854

    
1855
}
(3-3/4)