Project

General

Profile

Download (91.6 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.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.query.MatchMode;
70
import eu.etaxonomy.cdm.persistence.query.OrderHint;
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, queryString, null, matchMode, 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,String queryString, Classification classification,
155
            MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize,
156
            Integer pageNumber, List<String> propertyPaths) {
157

    
158
        boolean doCount = false;
159

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

    
162
        if (query != null){
163
            @SuppressWarnings("unchecked")
164
            List<TaxonBase> results = query.list();
165

    
166
            defaultBeanInitializer.initializeAll(results, propertyPaths);
167
            //TaxonComparatorSearch comp = new TaxonComparatorSearch();
168
            //Collections.sort(results, comp);
169
            return results;
170
        }
171

    
172
        return new ArrayList<TaxonBase>();
173

    
174
    }
175

    
176

    
177
    //new search for the editor, for performance issues the return values are only uuid and titleCache, to avoid the initialisation of all objects
178
    @Override
179
    @SuppressWarnings("unchecked")
180
    public List<UuidAndTitleCache<IdentifiableEntity>> getTaxaByNameForEditor(boolean doTaxa, boolean doSynonyms, boolean doNamesWithoutTaxa, boolean doMisappliedNames, String queryString, Classification classification,
181
            MatchMode matchMode, Set<NamedArea> namedAreas) {
182
//        long zstVorher;
183
//        long zstNachher;
184

    
185
        boolean doCount = false;
186
        List<UuidAndTitleCache<IdentifiableEntity>> resultObjects = new ArrayList<UuidAndTitleCache<IdentifiableEntity>>();
187
        if (doNamesWithoutTaxa){
188
        	List<? extends TaxonNameBase<?,?>> nameResult = taxonNameDao.findByName(queryString,matchMode, null, null, null, null);
189

    
190
        	for (TaxonNameBase name: nameResult){
191
        		if (name.getTaxonBases().size() == 0){
192
        			resultObjects.add(new UuidAndTitleCache(TaxonNameBase.class, name.getUuid(), name.getId(), name.getTitleCache()));
193
        		}
194
        	}
195
        	if (!doSynonyms && !doTaxa){
196
        		return resultObjects;
197
        	}
198
        }
199
        Query query = prepareTaxaByNameForEditor(doTaxa, doSynonyms, doMisappliedNames, "nameCache", queryString, classification, matchMode, namedAreas, doCount);
200

    
201

    
202
        if (query != null){
203
            List<Object[]> results = query.list();
204

    
205
            Object[] result;
206
            for(int i = 0; i<results.size();i++){
207
                result = results.get(i);
208

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

    
226

    
227

    
228
        }
229

    
230
        return resultObjects;
231

    
232
    }
233

    
234
    @Override
235
    public List<Taxon> getTaxaByCommonName(String queryString, Classification classification,
236
               MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize,
237
               Integer pageNumber, List<String> propertyPaths) {
238
        boolean doCount = false;
239
        Query query = prepareTaxaByCommonName(queryString, classification, matchMode, namedAreas, pageSize, pageNumber, doCount, false);
240
        if (query != null){
241
            List<Taxon> results = query.list();
242
            defaultBeanInitializer.initializeAll(results, propertyPaths);
243
            return results;
244
        }
245
        return new ArrayList<Taxon>();
246

    
247
    }
248

    
249
    /**
250
     * @param clazz
251
     * @param searchField the field in TaxonNameBase to be searched through usually either <code>nameCache</code> or <code>titleCache</code>
252
     * @param queryString
253
     * @param classification TODO
254
     * @param matchMode
255
     * @param namedAreas
256
     * @param pageSize
257
     * @param pageNumber
258
     * @param doCount
259
     * @return
260
     *
261
     *
262
     */
263
    private Query prepareTaxaByNameForEditor(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, String searchField, String queryString, Classification classification,
264
            MatchMode matchMode, Set<NamedArea> namedAreas, boolean doCount) {
265
        return prepareQuery(doTaxa, doSynonyms, doMisappliedNames, searchField, queryString,
266
                classification, matchMode, namedAreas, doCount, true);
267
    }
268

    
269
    /**
270
     * @param searchField
271
     * @param queryString
272
     * @param classification
273
     * @param matchMode
274
     * @param namedAreas
275
     * @param doCount
276
     * @param doNotReturnFullEntities
277
     *            if set true the seach method will not return synonym and taxon
278
     *            entities but an array containing the uuid, titleCache, and the
279
     *            DTYPE in lowercase letters.
280
     * @param clazz
281
     * @return
282
     */
283
    private Query prepareQuery(boolean doTaxa, boolean doSynonyms, boolean doIncludeMisappliedNames, String searchField, String queryString,
284
                Classification classification, MatchMode matchMode, Set<NamedArea> namedAreas, boolean doCount, boolean doNotReturnFullEntities){
285

    
286
            String hqlQueryString = matchMode.queryStringFrom(queryString);
287
            String selectWhat;
288
            if (doNotReturnFullEntities){
289
                selectWhat = "t.uuid, t.id, t.titleCache ";
290
            }else {
291
                selectWhat = (doCount ? "count(t)": "t");
292
            }
293

    
294
            String hql = "";
295
            Set<NamedArea> areasExpanded = new HashSet<NamedArea>();
296
            if(namedAreas != null && namedAreas.size() > 0){
297
                // expand areas and restrict by distribution area
298
                Query areaQuery = getSession().createQuery("select childArea from NamedArea as childArea left join childArea.partOf as parentArea where parentArea = :area");
299
                expandNamedAreas(namedAreas, areasExpanded, areaQuery);
300
            }
301
            boolean doAreaRestriction = areasExpanded.size() > 0;
302

    
303
            Set<UUID> namedAreasUuids = new HashSet<UUID>();
304
            for (NamedArea area:areasExpanded){
305
                namedAreasUuids.add(area.getUuid());
306
            }
307

    
308

    
309
            String [] subSelects = createHQLString(doTaxa, doSynonyms, doIncludeMisappliedNames, classification, areasExpanded, matchMode, searchField);
310
            String taxonSubselect = subSelects[1];
311
            String synonymSubselect = subSelects[2];
312
            String misappliedSelect = subSelects[0];
313

    
314

    
315
            /*if(classification != null ){
316
                if (!doIncludeMisappliedNames){
317
                    if(doAreaRestriction){
318

    
319
                        taxonSubselect = "select t.id from" +
320
                            " Distribution e" +
321
                            " join e.inDescription d" +
322
                            " join d.taxon t" +
323
                            " join t.name n " +
324
                            " join t.taxonNodes as tn "+
325
                            " where" +
326
                            " e.area.uuid in (:namedAreasUuids) AND" +
327
                            " tn.classification = :classification" +
328
                            " AND n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
329

    
330

    
331

    
332
                        synonymSubselect = "select s.id from" +
333
                            " Distribution e" +
334
                            " join e.inDescription d" +
335
                            " join d.taxon t" + // the taxa
336
                            " join t.taxonNodes as tn "+
337
                            " join t.synonymRelations sr" +
338
                            " join sr.relatedFrom s" + // the synonyms
339
                            " join s.name sn"+
340
                            " where" +
341
                            " e.area.uuid in (:namedAreasUuids) AND" +
342
                            " tn.classification = :classification" +
343
                            " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
344

    
345
                    } else {
346

    
347
                        taxonSubselect = "select t.id from" +
348
                            " Taxon t" +
349
                            " join t.name n " +
350
                            " join t.taxonNodes as tn "+
351
                            " where" +
352
                            " tn.classification = :classification" +
353
                            " AND n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
354

    
355
                        synonymSubselect = "select s.id from" +
356
                            " Taxon t" + // the taxa
357
                            " join t.taxonNodes as tn "+
358
                            " join t.synonymRelations sr" +
359
                            " join sr.relatedFrom s" + // the synonyms
360
                            " join s.name sn"+
361
                            " where" +
362
                            " tn.classification = :classification" +
363
                            " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
364
                    }
365
                }else{
366
                    if(doAreaRestriction){
367
                        if (!doTaxa && !doSynonyms ){
368
                            misappliedSelect = "select t.id from" +
369
                            " Distribution e" +
370
                            " join e.inDescription d" +
371
                            " join d.taxon t" +
372
                            " join t.name n " +
373
                            " join t.taxonNodes as tn "+
374
                            " left join t.relationsFromThisTaxon as rft" +
375
                            " left join rft.relatedTo as rt" +
376
                            " left join rt.taxonNodes as tn2" +
377
                            " left join rt.name as n2" +
378
                            " left join rft.type as rtype"+
379
                            " where" +
380
                            " e.area.uuid in (:namedAreasUuids) AND" +
381
                            " (tn.classification != :classification" +
382
                            " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString" +
383
                            " AND tn2.classification = :classification" +
384
                            " AND rtype = :rType )";
385

    
386
                        }else{
387
                            taxonSubselect = "select t.id from" +
388
                                " Distribution e" +
389
                                " join e.inDescription d" +
390
                                " join d.taxon t" +
391
                                " join t.name n " +
392
                                " join t.taxonNodes as tn "+
393
                                " left join t.relationsFromThisTaxon as rft" +
394
                                " left join rft.relatedTo as rt" +
395
                                " left join rt.taxonNodes as tn2" +
396
                                " left join rt.name as n2" +
397
                                " left join rft.type as rtype"+
398
                                " where" +
399
                                " e.area.uuid in (:namedAreasUuids) AND" +
400
                                " (tn.classification = :classification" +
401
                                " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString )" +
402
                                " OR"+
403
                                " (tn.classification != :classification" +
404
                                " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString" +
405
                                " AND tn2.classification = :classification" +
406
                                " AND rtype = :rType )";
407

    
408

    
409
                            synonymSubselect = "select s.id from" +
410
                                " Distribution e" +
411
                                " join e.inDescription d" +
412
                                " join d.taxon t" + // the taxa
413
                                " join t.taxonNodes as tn "+
414
                                " join t.synonymRelations sr" +
415
                                " join sr.relatedFrom s" + // the synonyms
416
                                " join s.name sn"+
417
                                " where" +
418
                                " e.area.uuid in (:namedAreasUuids) AND" +
419
                                " tn.classification != :classification" +
420
                                " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
421
                        }
422
                    } else {
423
                        if (!doTaxa && !doSynonyms ){
424
                            misappliedSelect = "select t.id from" +
425
                            " Distribution e" +
426
                            " join e.inDescription d" +
427
                            " join d.taxon t" +
428
                            " join t.name n " +
429
                            " join t.taxonNodes as tn "+
430
                            " left join t.relationsFromThisTaxon as rft" +
431
                            " left join rft.relatedTo as rt" +
432
                            " left join rt.taxonNodes as tn2" +
433
                            " left join rt.name as n2" +
434
                            " left join rft.type as rtype"+
435
                            " where" +
436
                            " (tn.classification != :classification" +
437
                            " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString" +
438
                            " AND tn2.classification = :classification" +
439
                            " AND rtype = :rType )";
440

    
441
                        }else{
442
                            taxonSubselect = "select t.id from" +
443
                                " Taxon t" +
444
                                " join t.name n " +
445
                                " join t.taxonNodes as tn "+
446
                                " left join t.relationsFromThisTaxon as rft" +
447
                                " left join rft.relatedTo as rt" +
448
                                " left join rt.taxonNodes as tn2" +
449
                                " left join rt.name as n2" +
450
                                " left join rft.type as rtype"+
451
                                " where " +
452
                                " (tn.classification = :classification" +
453
                                " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString )" +
454
                                " OR"+
455
                                " (tn.classification != :classification" +
456
                                " AND n." + searchField + " " + matchMode.getMatchOperator() + " :queryString" +
457
                                " AND tn2.classification = :classification" +
458
                                " AND rtype = :rType )";
459

    
460
                            synonymSubselect = "select s.id from" +
461
                                " Taxon t" + // the taxa
462
                                " join t.taxonNodes as tn "+
463
                                " join t.synonymRelations sr" +
464
                                " join sr.relatedFrom s" + // the synonyms
465
                                " join s.name sn"+
466
                                " where" +
467
                                " tn.classification != :classification" +
468
                                " AND sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
469
                        }
470
                    }
471
                }
472
            } else {
473

    
474
                if (!doIncludeMisappliedNames){
475
                    if(doAreaRestriction){
476
                        taxonSubselect = "select t.id from " +
477
                            " Distribution e" +
478
                            " join e.inDescription d" +
479
                            " join d.taxon t" +
480
                            " join t.name n "+
481
                            " where" +
482
                            (doAreaRestriction ? " e.area.uuid in (:namedAreasUuids) AND" : "") +
483
                            " n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
484

    
485
                        synonymSubselect = "select s.id from" +
486
                            " Distribution e" +
487
                            " join e.inDescription d" +
488
                            " join d.taxon t" + // the taxa
489
                            " join t.synonymRelations sr" +
490
                            " join sr.relatedFrom s" + // the synonyms
491
                            " join s.name sn"+
492
                            " where" +
493
                            (doAreaRestriction ? " e.area.uuid in (:namedAreasUuids) AND" : "") +
494
                            " sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
495

    
496
                    } else {
497

    
498
                        taxonSubselect = "select t.id from " +
499
                            " Taxon t" +
500
                            " join t.name n "+
501
                            " where" +
502
                            " n." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
503

    
504
                        synonymSubselect = "select s.id from" +
505
                            " Taxon t" + // the taxa
506
                            " join t.synonymRelations sr" +
507
                            " join sr.relatedFrom s" + // the synonyms
508
                            " join s.name sn"+
509
                            " where" +
510
                            " sn." + searchField +  " " + matchMode.getMatchOperator() + " :queryString";
511
                    }
512
                }else{
513

    
514
                }
515

    
516
            }*/
517

    
518
            logger.debug("taxonSubselect: " + taxonSubselect != null ? taxonSubselect: "NULL");
519
            logger.debug("synonymSubselect: " + synonymSubselect != null ? synonymSubselect: "NULL");
520

    
521
            Query subTaxon = null;
522
            Query subSynonym = null;
523
            Query subMisappliedNames = null;
524
            if(doTaxa){
525
                // find Taxa
526
                subTaxon = getSession().createQuery(taxonSubselect).setParameter("queryString", hqlQueryString);
527

    
528
                if(doAreaRestriction){
529
                    subTaxon.setParameterList("namedAreasUuids", namedAreasUuids);
530
                }
531
                if(classification != null){
532
                    subTaxon.setParameter("classification", classification);
533

    
534
                }
535

    
536

    
537
            }
538

    
539
            if(doSynonyms){
540
                // find synonyms
541
                subSynonym = getSession().createQuery(synonymSubselect).setParameter("queryString", hqlQueryString);
542

    
543
                if(doAreaRestriction){
544
                    subSynonym.setParameterList("namedAreasUuids", namedAreasUuids);
545
                }
546
                if(classification != null){
547
                    subSynonym.setParameter("classification", classification);
548
                }
549
            }
550
            if (doIncludeMisappliedNames ){
551
                subMisappliedNames = getSession().createQuery(misappliedSelect).setParameter("queryString", hqlQueryString);
552
                subMisappliedNames.setParameter("rType", TaxonRelationshipType.MISAPPLIED_NAME_FOR());
553
                if(doAreaRestriction){
554
                    subMisappliedNames.setParameterList("namedAreasUuids", namedAreasUuids);
555
                }
556
                if(classification != null){
557
                    subMisappliedNames.setParameter("classification", classification);
558
                }
559
            }
560

    
561
            List<Integer> taxa = new ArrayList<Integer>();
562
            List<Integer> synonyms = new ArrayList<Integer>();
563
            if (doSynonyms){
564
                synonyms = subSynonym.list();
565
            }
566
            if(doTaxa){
567
                taxa = subTaxon.list();
568
            }
569
            if (doIncludeMisappliedNames){
570
                taxa.addAll(subMisappliedNames.list());
571
            }
572

    
573
            //FIXME : the fourth element of the result should be a boolean, but in the case of a synonym
574
            // (which does require a check) a constant boolean (false) value needs to set. It seems that
575
            // hql cannot parse a constant boolean value in the select list clause. This implies that the
576
            // resulting object could be a Boolean or a String. The workaround for this is to convert the
577
            // resutling object into a String (using toString) and then create a new Boolean object from
578
            // String.
579
            if (doTaxa && doSynonyms){
580
                if(synonyms.size()>0 && taxa.size()>0){
581
                    hql = "select " + selectWhat;
582
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
583
                    // also return the computed isOrphaned flag
584
                    if (doNotReturnFullEntities &&  !doCount ){
585
                        hql += ", case when t.id in (:taxa) then 'taxon' else 'synonym' end, " +
586
                                " 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 ";
587
                    }
588
                    hql +=  " from %s t " +
589
                            " where (t.id in (:taxa) OR t.id in (:synonyms)) ";
590
                }else if (synonyms.size()>0 ){
591
                    hql = "select " + selectWhat;
592
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
593
                    // also return the computed isOrphaned flag
594
                    if (doNotReturnFullEntities &&  !doCount ){
595
                        hql += ", 'synonym', 'false' ";
596

    
597
                    }
598
                    hql +=  " from %s t " +
599
                            " where t.id in (:synonyms) ";
600

    
601
                } else if (taxa.size()>0 ){
602
                    hql = "select " + selectWhat;
603
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
604
                    // also return the computed isOrphaned flag
605
                    if (doNotReturnFullEntities &&  !doCount ){
606
                        hql += ", 'taxon', " +
607
                                " case when t.taxonNodes is empty and t.relationsFromThisTaxon is empty and t.relationsToThisTaxon is empty then true else false end ";
608
                    }
609
                    hql +=  " from %s t " +
610
                            " where t.id in (:taxa) ";
611

    
612
                } else{
613
                    hql = "select " + selectWhat + " from %s t";
614
                }
615
            } else if(doTaxa){
616
                if  (taxa.size()>0){
617
                    hql = "select " + selectWhat;
618
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
619
                    // also return the computed isOrphaned flag
620
                    if (doNotReturnFullEntities){
621
                        hql += ", 'taxon', " +
622
                                " case when t.taxonNodes is empty and t.relationsFromThisTaxon is empty and t.relationsToThisTaxon is empty then true else false end ";
623
                    }
624
                    hql +=  " from %s t " +
625
                            " where t.id in (:taxa) ";
626

    
627
                }else{
628
                    hql = "select " + selectWhat + " from %s t";
629
                }
630
            } else if(doSynonyms){
631
                if (synonyms.size()>0){
632

    
633
                    hql = "select " + selectWhat;
634
                    // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
635
                    // also return the computed isOrphaned flag
636
                    if (doNotReturnFullEntities){
637
                        hql += ", 'synonym', 'false' ";
638
                    }
639
                    hql +=  " from %s t " +
640
                            " where t.id in (:synonyms) ";
641
                }else{
642
                    hql = "select " + selectWhat + " from %s t";
643
                }
644
            } else if (doIncludeMisappliedNames){
645
                hql = "select " + selectWhat;
646
                // in doNotReturnFullEntities mode it is nesscary to also return the type of the matching entities:
647
                // also return the computed isOrphaned flag
648
                if (doNotReturnFullEntities){
649
                    hql += ", 'taxon', " +
650
                            " case when t.taxonNodes is empty and t.relationsFromThisTaxon is empty and t.relationsToThisTaxon is empty then true else false end ";
651
                }
652
                hql +=  " from %s t " +
653
                        " where t.id in (:taxa) ";
654

    
655
            }
656

    
657
            String classString;
658
            if (doTaxa && doSynonyms){
659
                classString = "TaxonBase";
660
            } else if (doTaxa){
661
                classString = "Taxon";
662
            } else if (doSynonyms){
663
                classString = "Synonym";
664
            } else{//only misappliedNames
665
                classString = "Taxon";
666
            }
667

    
668
            hql = String.format(hql, classString);
669

    
670

    
671
            if (hql == "") {
672
                return null;
673
            }
674
            if(!doCount){
675
                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";
676
            }
677

    
678
            logger.debug("hql: " + hql);
679
            Query query = getSession().createQuery(hql);
680

    
681

    
682
            if (doTaxa && doSynonyms){
683
                // find taxa and synonyms
684
                if (taxa.size()>0){
685
                    query.setParameterList("taxa", taxa);
686
                }
687
                if (synonyms.size()>0){
688
                    query.setParameterList("synonyms",synonyms);
689
                }
690
                if (taxa.size()== 0 && synonyms.size() == 0){
691
                    return null;
692
                }
693
            }else if(doTaxa){
694
                //find taxa
695
                if (taxa.size()>0){
696
                    query.setParameterList("taxa", taxa );
697
                }else{
698
                    logger.warn("there are no taxa for the query: " + queryString);
699
                    return null;
700
                }
701
            } else if(doSynonyms){
702
                // find synonyms
703
                if (synonyms.size()>0){
704
                    query.setParameterList("synonyms", synonyms);
705
                }else{
706
                    return null;
707
                }
708
            }	else{
709
                //only misappliedNames
710
                if (taxa.size()>0){
711
                    query.setParameterList("taxa", taxa );
712
                }else{
713
                    return null;
714
                }
715
            }
716

    
717
            return query;
718
    }
719

    
720

    
721
    /**
722
     * @param searchField the field in TaxonNameBase to be searched through usually either <code>nameCache</code> or <code>titleCache</code>
723
     * @param queryString
724
     * @param classification TODO
725
     * @param matchMode
726
     * @param namedAreas
727
     * @param pageSize
728
     * @param pageNumber
729
     * @param doCount
730
     * @param clazz
731
     * @return
732
     *
733
     * FIXME implement classification restriction & implement test: see {@link TaxonDaoHibernateImplTest#testCountTaxaByName()}
734
     */
735
    private Query prepareTaxaByName(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, String searchField, String queryString,
736
            Classification classification, MatchMode matchMode, Set<NamedArea> namedAreas, Integer pageSize, Integer pageNumber, boolean doCount) {
737

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

    
740
        if(pageSize != null &&  !doCount && query != null) {
741
            query.setMaxResults(pageSize);
742
            if(pageNumber != null) {
743
                query.setFirstResult(pageNumber * pageSize);
744
            }
745
        }
746

    
747
        return query;
748
    }
749

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

    
753
        String what = "select";
754
        if (doNotReturnFullEntities){
755
        	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 ";
756
        }else {
757
        	what += (doCount ? " count(t)": " t");
758
        }
759
        String hql= what + " from Taxon t " +
760
        "join t.descriptions d "+
761
        "join d.descriptionElements e " +
762
        "join e.feature f " +
763
        "where f.supportsCommonTaxonName = true and e.name "+matchMode.getMatchOperator()+" :queryString";//and ls.text like 'common%'";
764

    
765
        Query query = getSession().createQuery(hql);
766

    
767
        query.setParameter("queryString", matchMode.queryStringFrom(queryString));
768

    
769
        if(pageSize != null &&  !doCount) {
770
            query.setMaxResults(pageSize);
771
            if(pageNumber != null) {
772
                query.setFirstResult(pageNumber * pageSize);
773
            }
774
        }
775
        return query;
776
    }
777

    
778
    @Override
779
    public long countTaxaByName(boolean doTaxa, boolean doSynonyms, boolean doMisappliedNames, String queryString, Classification classification,
780
        MatchMode matchMode, Set<NamedArea> namedAreas) {
781

    
782
        boolean doCount = true;
783
        /*
784
        boolean doTaxa = true;
785
        boolean doSynonyms = true;
786
        if (clazz.equals(Taxon.class)){
787
            doSynonyms = false;
788
        } else if (clazz.equals(Synonym.class)){
789
            doTaxa = false;
790
        }
791
        */
792

    
793

    
794
        Query query = prepareTaxaByName(doTaxa, doSynonyms, doMisappliedNames, "nameCache", queryString, classification, matchMode, namedAreas, null, null, doCount);
795
        if (query != null) {
796
            return (Long)query.uniqueResult();
797
        }else{
798
            return 0;
799
        }
800
    }
801

    
802
    /**
803
     * @param namedAreas
804
     * @param areasExpanded
805
     * @param areaQuery
806
     */
807
    private void expandNamedAreas(Collection<NamedArea> namedAreas, Set<NamedArea> areasExpanded, Query areaQuery) {
808
        List<NamedArea> childAreas;
809
        for(NamedArea a : namedAreas){
810
            areasExpanded.add(a);
811
            areaQuery.setParameter("area", a);
812
            childAreas = areaQuery.list();
813
            if(childAreas.size() > 0){
814
                areasExpanded.addAll(childAreas);
815
                expandNamedAreas(childAreas, areasExpanded, areaQuery);
816
            }
817
        }
818
    }
819

    
820

    
821
    @Override
822
    public List<TaxonBase> getAllTaxonBases(Integer pagesize, Integer page) {
823
        return super.list(pagesize, page);
824
    }
825

    
826
    @Override
827
    public List<Synonym> getAllSynonyms(Integer limit, Integer start) {
828
        Criteria criteria = getSession().createCriteria(Synonym.class);
829

    
830
        if(limit != null) {
831
            criteria.setFirstResult(start);
832
            criteria.setMaxResults(limit);
833
        }
834

    
835
        return criteria.list();
836
    }
837

    
838
    @Override
839
    public List<Taxon> getAllTaxa(Integer limit, Integer start) {
840
        Criteria criteria = getSession().createCriteria(Taxon.class);
841

    
842
        if(limit != null) {
843
            criteria.setFirstResult(start);
844
            criteria.setMaxResults(limit);
845
        }
846

    
847
        return criteria.list();
848
    }
849

    
850
    @Override
851
    public List<RelationshipBase> getAllRelationships(/*Class<? extends RelationshipBase> clazz,*/ Integer limit, Integer start) {
852
        Class<? extends RelationshipBase> clazz = RelationshipBase.class;  //preliminary, see #2653
853
        AuditEvent auditEvent = getAuditEventFromContext();
854
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
855
            // for some reason the HQL .class discriminator didn't work here so I created this preliminary
856
            // implementation for now. Should be cleaned in future.
857

    
858
            List<RelationshipBase> result = new ArrayList<RelationshipBase>();
859

    
860
            int taxRelSize = countAllRelationships(TaxonRelationship.class);
861

    
862
            if (taxRelSize > start){
863

    
864
                String hql = " FROM TaxonRelationship as rb ORDER BY rb.id ";
865
                Query query = getSession().createQuery(hql);
866
                query.setFirstResult(start);
867
                if (limit != null){
868
                    query.setMaxResults(limit);
869
                }
870
                result = query.list();
871
            }
872
            limit = limit - result.size();
873
            if (limit > 0){
874
                String hql = " FROM SynonymRelationship as rb ORDER BY rb.id ";
875
                Query query = getSession().createQuery(hql);
876
                start = (taxRelSize > start) ? 0 : (start - taxRelSize);
877
                query.setFirstResult(start);
878
                if (limit != null){
879
                    query.setMaxResults(limit);
880
                }
881
                result.addAll(query.list());
882
            }
883
            return result;
884

    
885
        } else {
886
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(clazz,auditEvent.getRevisionNumber());
887
            return query.getResultList();
888
        }
889
    }
890

    
891
    @Override
892
    public UUID delete(TaxonBase taxonBase) throws DataAccessException{
893
        if (taxonBase == null){
894
            logger.warn("TaxonBase was 'null'");
895
            return null;
896
        }
897

    
898
        // Merge the object in if it is detached
899
        //
900
        // I think this is preferable to catching lazy initialization errors
901
        // as that solution only swallows and hides the exception, but doesn't
902
        // actually solve it.
903
        getSession().merge(taxonBase);
904

    
905
        taxonBase.removeSources();
906

    
907
        if (taxonBase instanceof Taxon){ //	is Taxon
908
            for (Iterator<TaxonRelationship> iterator = ((Taxon)taxonBase).getRelationsFromThisTaxon().iterator(); iterator.hasNext();){
909
                TaxonRelationship relationFromThisTaxon = iterator.next();
910

    
911
            }
912
        }
913

    
914
       return super.delete(taxonBase);
915

    
916
    }
917

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

    
921
        boolean doCount = false;
922
        Query query = prepareTaxaByName(doTaxa, doSynonyms, false, "titleCache", queryString, classification, matchMode, namedAreas, pageSize, pageNumber, doCount);
923
        if (query != null){
924
            List<TaxonBase> results = query.list();
925
            defaultBeanInitializer.initializeAll(results, propertyPaths);
926
            return results;
927
        }
928
        return new ArrayList<TaxonBase>();
929

    
930
    }
931

    
932
    @Override
933
    public TaxonBase findByUuid(UUID uuid, List<Criterion> criteria, List<String> propertyPaths) {
934

    
935
        Criteria crit = getSession().createCriteria(type);
936

    
937
        if (uuid != null) {
938
            crit.add(Restrictions.eq("uuid", uuid));
939
        } else {
940
            logger.warn("UUID is NULL");
941
            return null;
942
        }
943
        if(criteria != null){
944
            for (Criterion criterion : criteria) {
945
                crit.add(criterion);
946
            }
947
        }
948
        crit.addOrder(Order.asc("uuid"));
949

    
950
        List<? extends TaxonBase> results = crit.list();
951
        if (results.size() == 1) {
952
            defaultBeanInitializer.initializeAll(results, propertyPaths);
953
            TaxonBase taxon = results.iterator().next();
954
            return taxon;
955
        } else if (results.size() > 1) {
956
            logger.error("Multiple results for UUID: " + uuid);
957
        } else if (results.size() == 0) {
958
            logger.info("No results for UUID: " + uuid);
959
        }
960

    
961
        return null;
962
    }
963

    
964
    @Override
965
    public List<? extends TaxonBase> findByUuids(List<UUID> uuids, List<Criterion> criteria, List<String> propertyPaths) {
966

    
967
        Criteria crit = getSession().createCriteria(type);
968

    
969
        if (uuids != null) {
970
            crit.add(Restrictions.in("uuid", uuids));
971
        } else {
972
            logger.warn("List<UUID> uuids is NULL");
973
            return null;
974
        }
975
        if(criteria != null){
976
            for (Criterion criterion : criteria) {
977
                crit.add(criterion);
978
            }
979
        }
980
        crit.addOrder(Order.asc("uuid"));
981

    
982
        List<? extends TaxonBase> results = crit.list();
983

    
984
        defaultBeanInitializer.initializeAll(results, propertyPaths);
985
        return results;
986
    }
987

    
988
    @Override
989
    public int countMatchesByName(String queryString, MatchMode matchMode, boolean onlyAcccepted) {
990
        checkNotInPriorView("TaxonDaoHibernateImpl.countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted)");
991
        Criteria crit = getSession().createCriteria(type);
992
        crit.add(Restrictions.ilike("titleCache", matchMode.queryStringFrom(queryString)));
993
        crit.setProjection(Projections.rowCount());
994
        int result = ((Number)crit.list().get(0)).intValue();
995
        return result;
996
    }
997

    
998

    
999
    @Override
1000
    public int countMatchesByName(String queryString, MatchMode matchMode, boolean onlyAcccepted, List<Criterion> criteria) {
1001
        checkNotInPriorView("TaxonDaoHibernateImpl.countMatchesByName(String queryString, ITitledDao.MATCH_MODE matchMode, boolean onlyAcccepted, List<Criterion> criteria)");
1002
        Criteria crit = getSession().createCriteria(type);
1003
        crit.add(Restrictions.ilike("titleCache", matchMode.queryStringFrom(queryString)));
1004
        if(criteria != null){
1005
            for (Criterion criterion : criteria) {
1006
                crit.add(criterion);
1007
            }
1008
        }
1009
        crit.setProjection(Projections.rowCount());
1010
        int result = ((Number)crit.list().get(0)).intValue();
1011
        return result;
1012
    }
1013

    
1014
    @Override
1015
    public int countTaxonRelationships(Taxon taxon, TaxonRelationshipType type, Direction direction) {
1016
        AuditEvent auditEvent = getAuditEventFromContext();
1017
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1018
            Query query = null;
1019

    
1020
            if(type == null) {
1021
                query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship."+direction+" = :relatedTaxon");
1022
            } else {
1023
                query = getSession().createQuery("select count(taxonRelationship) from TaxonRelationship taxonRelationship where taxonRelationship."+direction+" = :relatedTaxon and taxonRelationship.type = :type");
1024
                query.setParameter("type",type);
1025
            }
1026
            query.setParameter("relatedTaxon", taxon);
1027

    
1028
            return ((Long)query.uniqueResult()).intValue();
1029
        } else {
1030
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());
1031
            query.add(AuditEntity.relatedId(direction.toString()).eq(taxon.getId()));
1032
            query.addProjection(AuditEntity.id().count());
1033

    
1034
            if(type != null) {
1035
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1036
            }
1037

    
1038
            return ((Long)query.getSingleResult()).intValue();
1039
        }
1040
    }
1041

    
1042
    @Override
1043
    public int countSynonyms(Taxon taxon, SynonymRelationshipType type) {
1044
        AuditEvent auditEvent = getAuditEventFromContext();
1045
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1046
            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);
1047

    
1048
            criteria.add(Restrictions.eq("relatedTo", taxon));
1049
            if(type != null) {
1050
                criteria.add(Restrictions.eq("type", type));
1051
            }
1052
            criteria.setProjection(Projections.rowCount());
1053
            return ((Number)criteria.uniqueResult()).intValue();
1054
        } else {
1055
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());
1056
            query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));
1057
            query.addProjection(AuditEntity.id().count());
1058

    
1059
            if(type != null) {
1060
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1061
            }
1062

    
1063
            return ((Long)query.getSingleResult()).intValue();
1064
        }
1065
    }
1066

    
1067
    @Override
1068
    public int countSynonyms(Synonym synonym, SynonymRelationshipType type) {
1069
        AuditEvent auditEvent = getAuditEventFromContext();
1070
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1071
            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);
1072

    
1073
            criteria.add(Restrictions.eq("relatedFrom", synonym));
1074
            if(type != null) {
1075
                criteria.add(Restrictions.eq("type", type));
1076
            }
1077

    
1078
            criteria.setProjection(Projections.rowCount());
1079
            return ((Number)criteria.uniqueResult()).intValue();
1080
        } else {
1081
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());
1082
            query.add(AuditEntity.relatedId("relatedFrom").eq(synonym.getId()));
1083
            query.addProjection(AuditEntity.id().count());
1084

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

    
1089
            return ((Long)query.getSingleResult()).intValue();
1090
        }
1091
    }
1092

    
1093
    @Override
1094
    public int countTaxaByName(Class<? extends TaxonBase> clazz, String genusOrUninomial, String infraGenericEpithet, String specificEpithet,	String infraSpecificEpithet, Rank rank) {
1095
        checkNotInPriorView("TaxonDaoHibernateImpl.countTaxaByName(Boolean accepted, String genusOrUninomial,	String infraGenericEpithet, String specificEpithet,	String infraSpecificEpithet, Rank rank)");
1096
        Criteria criteria = null;
1097

    
1098
        criteria = getSession().createCriteria(clazz);
1099

    
1100
        criteria.setFetchMode( "name", FetchMode.JOIN );
1101
        criteria.createAlias("name", "name");
1102

    
1103
        if(genusOrUninomial == null) {
1104
            criteria.add(Restrictions.isNull("name.genusOrUninomial"));
1105
        } else if(!genusOrUninomial.equals("*")) {
1106
            criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));
1107
        }
1108

    
1109
        if(infraGenericEpithet == null) {
1110
            criteria.add(Restrictions.isNull("name.infraGenericEpithet"));
1111
        } else if(!infraGenericEpithet.equals("*")) {
1112
            criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));
1113
        }
1114

    
1115
        if(specificEpithet == null) {
1116
            criteria.add(Restrictions.isNull("name.specificEpithet"));
1117
        } else if(!specificEpithet.equals("*")) {
1118
            criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));
1119

    
1120
        }
1121

    
1122
        if(infraSpecificEpithet == null) {
1123
            criteria.add(Restrictions.isNull("name.infraSpecificEpithet"));
1124
        } else if(!infraSpecificEpithet.equals("*")) {
1125
            criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));
1126
        }
1127

    
1128
        if(rank != null) {
1129
            criteria.add(Restrictions.eq("name.rank", rank));
1130
        }
1131

    
1132
        criteria.setProjection(Projections.projectionList().add(Projections.rowCount()));
1133

    
1134
        return ((Number)criteria.uniqueResult()).intValue();
1135
    }
1136

    
1137
    @Override
1138
    public List<TaxonBase> findTaxaByName(Class<? extends TaxonBase> clazz, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, String authorship, Rank rank, Integer pageSize,	Integer pageNumber) {
1139
        checkNotInPriorView("TaxonDaoHibernateImpl.findTaxaByName(Boolean accepted, String genusOrUninomial, String infraGenericEpithet, String specificEpithet, String infraSpecificEpithet, String authorship, Rank rank, Integer pageSize,	Integer pageNumber)");
1140
        Criteria criteria = null;
1141
        if (clazz == null){
1142
            criteria = getSession().createCriteria(TaxonBase.class);
1143
        } else{
1144
            criteria = getSession().createCriteria(clazz);
1145
        }
1146
        criteria.setFetchMode( "name", FetchMode.JOIN );
1147
        criteria.createAlias("name", "name");
1148

    
1149
        if(genusOrUninomial == null) {
1150
            criteria.add(Restrictions.isNull("name.genusOrUninomial"));
1151
        } else if(!genusOrUninomial.equals("*")) {
1152
            criteria.add(Restrictions.eq("name.genusOrUninomial", genusOrUninomial));
1153
        }
1154

    
1155
        if(infraGenericEpithet == null) {
1156
            criteria.add(Restrictions.isNull("name.infraGenericEpithet"));
1157
        } else if(!infraGenericEpithet.equals("*")) {
1158
            criteria.add(Restrictions.eq("name.infraGenericEpithet", infraGenericEpithet));
1159
        }
1160

    
1161
        if(specificEpithet == null) {
1162
            criteria.add(Restrictions.isNull("name.specificEpithet"));
1163
        } else if(!specificEpithet.equals("*")) {
1164
            criteria.add(Restrictions.eq("name.specificEpithet", specificEpithet));
1165

    
1166
        }
1167

    
1168
        if(infraSpecificEpithet == null) {
1169
            criteria.add(Restrictions.isNull("name.infraSpecificEpithet"));
1170
        } else if(!infraSpecificEpithet.equals("*")) {
1171
            criteria.add(Restrictions.eq("name.infraSpecificEpithet", infraSpecificEpithet));
1172
        }
1173

    
1174
        if(authorship == null) {
1175
            criteria.add(Restrictions.eq("name.authorshipCache", ""));
1176
        } else if(!authorship.equals("*")) {
1177
            criteria.add(Restrictions.eq("name.authorshipCache", authorship));
1178
        }
1179

    
1180
        if(rank != null) {
1181
            criteria.add(Restrictions.eq("name.rank", rank));
1182
        }
1183

    
1184
        if(pageSize != null) {
1185
            criteria.setMaxResults(pageSize);
1186
            if(pageNumber != null) {
1187
                criteria.setFirstResult(pageNumber * pageSize);
1188
            } else {
1189
                criteria.setFirstResult(0);
1190
            }
1191
        }
1192

    
1193
        return criteria.list();
1194
    }
1195

    
1196
    @Override
1197
    public List<TaxonRelationship> getTaxonRelationships(Taxon taxon, TaxonRelationshipType type,
1198
            Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths, Direction direction) {
1199

    
1200
        AuditEvent auditEvent = getAuditEventFromContext();
1201
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1202

    
1203
            Criteria criteria = getSession().createCriteria(TaxonRelationship.class);
1204

    
1205
            if(direction != null) {
1206
                criteria.add(Restrictions.eq(direction.name(), taxon));
1207
            } else {
1208
                criteria.add(Restrictions.or(
1209
                        Restrictions.eq(Direction.relatedFrom.name(), taxon),
1210
                        Restrictions.eq(Direction.relatedTo.name(), taxon))
1211
                    );
1212
            }
1213

    
1214
            if(type != null) {
1215
                criteria.add(Restrictions.eq("type", type));
1216
            }
1217

    
1218
            addOrder(criteria,orderHints);
1219

    
1220
            if(pageSize != null) {
1221
                criteria.setMaxResults(pageSize);
1222
                if(pageNumber != null) {
1223
                    criteria.setFirstResult(pageNumber * pageSize);
1224
                } else {
1225
                    criteria.setFirstResult(0);
1226
                }
1227
            }
1228

    
1229
            List<TaxonRelationship> result = criteria.list();
1230
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1231

    
1232
            return result;
1233
        } else {
1234
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());
1235
            query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));
1236

    
1237
            if(type != null) {
1238
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1239
            }
1240

    
1241
            if(pageSize != null) {
1242
                query.setMaxResults(pageSize);
1243
                if(pageNumber != null) {
1244
                    query.setFirstResult(pageNumber * pageSize);
1245
                } else {
1246
                    query.setFirstResult(0);
1247
                }
1248
            }
1249

    
1250
            List<TaxonRelationship> result = query.getResultList();
1251
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1252

    
1253
            // Ugly, but for now, there is no way to sort on a related entity property in Envers,
1254
            // and we can't live without this functionality in CATE as it screws up the whole
1255
            // taxon tree thing
1256
            if(orderHints != null && !orderHints.isEmpty()) {
1257
                SortedSet<TaxonRelationship> sortedList = new TreeSet<TaxonRelationship>(new TaxonRelationshipFromTaxonComparator());
1258
                sortedList.addAll(result);
1259
                return new ArrayList<TaxonRelationship>(sortedList);
1260
            }
1261

    
1262
            return result;
1263
        }
1264
    }
1265

    
1266
    class TaxonRelationshipFromTaxonComparator implements Comparator<TaxonRelationship> {
1267

    
1268
        @Override
1269
        public int compare(TaxonRelationship o1, TaxonRelationship o2) {
1270
            return o1.getFromTaxon().getTitleCache().compareTo(o2.getFromTaxon().getTitleCache());
1271
        }
1272

    
1273
    }
1274

    
1275
    class SynonymRelationshipFromTaxonComparator implements Comparator<SynonymRelationship> {
1276

    
1277
        @Override
1278
        public int compare(SynonymRelationship o1, SynonymRelationship o2) {
1279
            return o1.getSynonym().getTitleCache().compareTo(o2.getSynonym().getTitleCache());
1280
        }
1281

    
1282
    }
1283

    
1284
    @Override
1285
    public List<SynonymRelationship> getSynonyms(Taxon taxon, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
1286
        AuditEvent auditEvent = getAuditEventFromContext();
1287
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1288
            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);
1289

    
1290
            criteria.add(Restrictions.eq("relatedTo", taxon));
1291
            if(type != null) {
1292
                criteria.add(Restrictions.eq("type", type));
1293
            }
1294

    
1295
            addOrder(criteria,orderHints);
1296

    
1297
            if(pageSize != null) {
1298
                criteria.setMaxResults(pageSize);
1299
                if(pageNumber != null) {
1300
                    criteria.setFirstResult(pageNumber * pageSize);
1301
                } else {
1302
                    criteria.setFirstResult(0);
1303
                }
1304
            }
1305

    
1306
            List<SynonymRelationship> result = criteria.list();
1307
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1308

    
1309
            return result;
1310
        } else {
1311
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());
1312
            query.add(AuditEntity.relatedId("relatedTo").eq(taxon.getId()));
1313

    
1314
            if(type != null) {
1315
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1316
            }
1317

    
1318
            if(pageSize != null) {
1319
                query.setMaxResults(pageSize);
1320
                if(pageNumber != null) {
1321
                    query.setFirstResult(pageNumber * pageSize);
1322
                } else {
1323
                    query.setFirstResult(0);
1324
                }
1325
            }
1326

    
1327
            List<SynonymRelationship> result = query.getResultList();
1328
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1329

    
1330
            return result;
1331
        }
1332
    }
1333

    
1334
    @Override
1335
    public List<SynonymRelationship> getSynonyms(Synonym synonym, SynonymRelationshipType type, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
1336
        AuditEvent auditEvent = getAuditEventFromContext();
1337
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1338
            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);
1339

    
1340
            criteria.add(Restrictions.eq("relatedFrom", synonym));
1341
            if(type != null) {
1342
                criteria.add(Restrictions.eq("type", type));
1343
            }
1344

    
1345
            addOrder(criteria,orderHints);
1346

    
1347
            if(pageSize != null) {
1348
                criteria.setMaxResults(pageSize);
1349
                if(pageNumber != null) {
1350
                    criteria.setFirstResult(pageNumber * pageSize);
1351
                } else {
1352
                    criteria.setFirstResult(0);
1353
                }
1354
            }
1355

    
1356
            List<SynonymRelationship> result = criteria.list();
1357
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1358

    
1359
            return result;
1360
        } else {
1361
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(SynonymRelationship.class,auditEvent.getRevisionNumber());
1362
            query.add(AuditEntity.relatedId("relatedFrom").eq(synonym.getId()));
1363

    
1364
            if(type != null) {
1365
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1366
            }
1367

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

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

    
1380
            return result;
1381
        }
1382
    }
1383

    
1384
    @Override
1385
    public void rebuildIndex() {
1386
        FullTextSession fullTextSession = Search.getFullTextSession(getSession());
1387

    
1388
        for(TaxonBase taxonBase : list(null,null)) { // re-index all taxon base
1389
            Hibernate.initialize(taxonBase.getName());
1390
            fullTextSession.index(taxonBase);
1391
        }
1392
        fullTextSession.flushToIndexes();
1393
    }
1394

    
1395
    @Override
1396
    public String suggestQuery(String queryString) {
1397
        throw new RuntimeException("Query suggestion currently not implemented in TaxonDaoHibernateImpl");
1398
//        checkNotInPriorView("TaxonDaoHibernateImpl.suggestQuery(String queryString)");
1399
//        String alternativeQueryString = null;
1400
//        if (alternativeSpellingSuggestionParser != null) {
1401
//            try {
1402
//
1403
//                alternativeSpellingSuggestionParser.parse(queryString);
1404
//                org.apache.lucene.search.Query alternativeQuery = alternativeSpellingSuggestionParser.suggest(queryString);
1405
//                if (alternativeQuery != null) {
1406
//                    alternativeQueryString = alternativeQuery
1407
//                            .toString("name.titleCache");
1408
//                }
1409
//
1410
//            } catch (ParseException e) {
1411
//                throw new QueryParseException(e, queryString);
1412
//            }
1413
//        }
1414
//        return alternativeQueryString;
1415
    }
1416

    
1417
    @Override
1418
    public List<Taxon> listAcceptedTaxaFor(Synonym synonym, Classification classificationFilter, Integer pageSize, Integer pageNumber,
1419
            List<OrderHint> orderHints, List<String> propertyPaths){
1420

    
1421
        String hql = prepareListAcceptedTaxaFor(classificationFilter, orderHints, false);
1422

    
1423
        Query query = getSession().createQuery(hql);
1424

    
1425
        query.setParameter("synonym", synonym);
1426

    
1427
        if(classificationFilter != null){
1428
            query.setParameter("classificationFilter", classificationFilter);
1429
        }
1430

    
1431

    
1432
        if(pageSize != null) {
1433
            query.setMaxResults(pageSize);
1434
            if(pageNumber != null) {
1435
                query.setFirstResult(pageNumber * pageSize);
1436
            }
1437
        }
1438

    
1439
        @SuppressWarnings("unchecked")
1440
        List<Taxon> result = query.list();
1441

    
1442
        defaultBeanInitializer.initializeAll(result, propertyPaths);
1443

    
1444
        return result;
1445

    
1446
    }
1447

    
1448
    @Override
1449
    public long countAcceptedTaxaFor(Synonym synonym, Classification classificationFilter){
1450

    
1451
        String hql = prepareListAcceptedTaxaFor(classificationFilter, null, true);
1452

    
1453
        Query query = getSession().createQuery(hql);
1454

    
1455
        query.setParameter("synonym", synonym);
1456

    
1457
        if(classificationFilter != null){
1458
            query.setParameter("classificationFilter", classificationFilter);
1459
        }
1460

    
1461
        Long count = Long.parseLong(query.uniqueResult().toString());
1462

    
1463
        return count;
1464

    
1465
    }
1466

    
1467

    
1468
    /**
1469
     * @param classificationFilter
1470
     * @param orderHints
1471
     * @return
1472
     */
1473
    private String prepareListAcceptedTaxaFor(Classification classificationFilter, List<OrderHint> orderHints, boolean doCount) {
1474

    
1475
        String hql;
1476
        String hqlSelect = "select " + (doCount? "count(taxon)" : "taxon") + " from Taxon as taxon left join taxon.synonymRelations as synRel ";
1477
        String hqlWhere = " where synRel.relatedFrom = :synonym";
1478

    
1479
        if(classificationFilter != null){
1480
            hqlSelect += " left join taxon.taxonNodes AS taxonNode";
1481
            hqlWhere += " and taxonNode.classification = :classificationFilter";
1482
        }
1483
        hql = hqlSelect + hqlWhere + orderByClause(orderHints, "taxon");
1484
        return hql;
1485
    }
1486
    @Override
1487
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, Integer limit, String pattern) {
1488
        int classificationId = classification.getId();
1489
        // StringBuffer excludeUuids = new StringBuffer();
1490

    
1491
         String queryString = "SELECT nodes.uuid, nodes.id, taxon.titleCache FROM TaxonNode AS nodes JOIN nodes.taxon as taxon WHERE nodes.classification.id = " + classificationId ;
1492

    
1493
         if (pattern != null){
1494
             pattern = pattern.replace("*", "%");
1495
             queryString = queryString + " AND taxon.titleCache like (:pattern)" ;
1496
         }
1497

    
1498
         Query query = getSession().createQuery(queryString);
1499

    
1500

    
1501
         if (limit != null){
1502
             query.setMaxResults(limit);
1503
         }
1504

    
1505
         if (pattern != null){
1506
             query.setParameter("pattern", pattern);
1507
         }
1508
         @SuppressWarnings("unchecked")
1509
         List<Object[]> result = query.list();
1510

    
1511
         if(result.size() == 0){
1512
             return null;
1513
         }else{
1514
             List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<UuidAndTitleCache<TaxonNode>>(result.size());
1515

    
1516
             for (Object object : result){
1517

    
1518
                 Object[] objectArray = (Object[]) object;
1519

    
1520
                 UUID uuid = (UUID)objectArray[0];
1521
                 Integer id = (Integer) objectArray[1];
1522
                 String titleCache = (String) objectArray[2];
1523

    
1524
                 list.add(new UuidAndTitleCache<TaxonNode>(TaxonNode.class, uuid, id, titleCache));
1525
             }
1526

    
1527
             return list;
1528
         }
1529
    }
1530

    
1531

    
1532
    @Override
1533
    public TaxonBase find(LSID lsid) {
1534
        TaxonBase<?> taxonBase = super.find(lsid);
1535
        if(taxonBase != null) {
1536
            List<String> propertyPaths = new ArrayList<String>();
1537
            propertyPaths.add("createdBy");
1538
            propertyPaths.add("updatedBy");
1539
            propertyPaths.add("name");
1540
            propertyPaths.add("sec");
1541
            propertyPaths.add("relationsToThisTaxon");
1542
            propertyPaths.add("relationsToThisTaxon.fromTaxon");
1543
            propertyPaths.add("relationsToThisTaxon.toTaxon");
1544
            propertyPaths.add("relationsFromThisTaxon");
1545
            propertyPaths.add("relationsFromThisTaxon.toTaxon");
1546
            propertyPaths.add("relationsToThisTaxon.type");
1547
            propertyPaths.add("synonymRelations");
1548
            propertyPaths.add("synonymRelations.synonym");
1549
            propertyPaths.add("synonymRelations.type");
1550
            propertyPaths.add("descriptions");
1551

    
1552
            defaultBeanInitializer.initialize(taxonBase, propertyPaths);
1553
        }
1554
        return taxonBase;
1555
    }
1556

    
1557
    public List<TaxonBase> getTaxaByCommonName(String queryString,
1558
            Classification classification, MatchMode matchMode,
1559
            Set<NamedArea> namedAreas, Integer pageSize, Integer pageNumber) {
1560
        logger.warn("getTaxaByCommonName not yet implemented.");
1561
        return null;
1562
    }
1563

    
1564

    
1565

    
1566

    
1567
/*	private void xxx(List<SynonymRelationship> synonymRelationships, HashMap <UUID, ZoologicalName> zooHashMap, SynonymRelationshipType type, String addString){
1568

    
1569
        for (SynonymRelationship synonymRelation:synonymRelationships){
1570
            TaxonNameBase synName;
1571
            NonViralName inferredSynName;
1572
            Synonym syn = synonymRelation.getSynonym();
1573
            HibernateProxyHelper.deproxy(syn);
1574

    
1575
            synName = syn.getName();
1576
            ZoologicalName zooName = zooHashMap.get(synName.getUuid());
1577
            String synGenusName = zooName.getGenusOrUninomial();
1578

    
1579
            switch(type.getId()){
1580
            case SynonymRelationshipType.INFERRED_EPITHET_OF().getId():
1581
                inferredSynName.setSpecificEpithet(addString);
1582
                break;
1583
            case SynonymRelationshipType.INFERRED_GENUS_OF().getId():
1584
                break;
1585
            case SynonymRelationshipType.POTENTIAL_COMBINATION_OF().getId():
1586
                break;
1587
            default:
1588
            }
1589
            if (!synonymsGenus.contains(synGenusName)){
1590
                synonymsGenus.add(synGenusName);
1591
            }
1592
            inferredSynName = NonViralName.NewInstance(Rank.SPECIES());
1593
            inferredSynName.setSpecificEpithet(epithetOfTaxon);
1594
            inferredSynName.setGenusOrUninomial(synGenusName);
1595
            inferredEpithet = Synonym.NewInstance(inferredSynName, null);
1596
            taxon.addSynonym(inferredEpithet, SynonymRelationshipType.INFERRED_GENUS_OF());
1597
            inferredSynonyms.add(inferredEpithet);
1598
            inferredSynName.generateTitle();
1599
            taxonNames.add(inferredSynName.getNameCache());
1600
        }
1601

    
1602

    
1603
        if (!taxonNames.isEmpty()){
1604
        List<String> synNotInCDM = this.taxaByNameNotInDB(taxonNames);
1605
        ZoologicalName name;
1606
        if (!synNotInCDM.isEmpty()){
1607
            for (Synonym syn :inferredSynonyms){
1608
                name =zooHashMap.get(syn.getName().getUuid());
1609
                if (!synNotInCDM.contains(name.getNameCache())){
1610
                    inferredSynonyms.remove(syn);
1611
                }
1612
            }
1613
        }
1614
        }
1615
    }*/
1616

    
1617
    @Override
1618
    public int countAllRelationships() {
1619
        return countAllRelationships(null);
1620
    }
1621

    
1622

    
1623
    //FIXME add to interface or make private
1624
    public int countAllRelationships(Class<? extends RelationshipBase> clazz) {
1625
        if (clazz != null && ! TaxonRelationship.class.isAssignableFrom(clazz) && ! SynonymRelationship.class.isAssignableFrom(clazz) ){
1626
            throw new RuntimeException("Class must be assignable by a taxon or snonym relation");
1627
        }
1628
        int size = 0;
1629

    
1630
        if (clazz == null || TaxonRelationship.class.isAssignableFrom(clazz)){
1631
            String hql = " SELECT count(rel) FROM TaxonRelationship rel";
1632
            size += (Long)getSession().createQuery(hql).list().get(0);
1633
        }
1634
        if (clazz == null || SynonymRelationship.class.isAssignableFrom(clazz)){
1635
            String hql = " SELECT count(rel) FROM SynonymRelationship rel";
1636
            size += (Long)getSession().createQuery(hql).list().get(0);
1637
        }
1638
        return size;
1639
    }
1640

    
1641
    @Override
1642
    public List<String> taxaByNameNotInDB(List<String> taxonNames){
1643
        List<TaxonBase> notInDB = new ArrayList<TaxonBase>();
1644
        //get all taxa, already in db
1645
        Query query = getSession().createQuery("from TaxonNameBase t where t.nameCache IN (:taxonList)");
1646
        query.setParameterList("taxonList", taxonNames);
1647
        List<TaxonNameBase> taxaInDB = query.list();
1648
        //compare the original list with the result of the query
1649
        for (TaxonNameBase taxonName: taxaInDB){
1650
            if (taxonName.isInstanceOf(NonViralName.class)) {
1651
                NonViralName nonViralName = CdmBase.deproxy(taxonName, NonViralName.class);
1652
                String nameCache = nonViralName.getNameCache();
1653
                if (taxonNames.contains(nameCache)){
1654
                    taxonNames.remove(nameCache);
1655
                }
1656
            }
1657
        }
1658

    
1659
        return taxonNames;
1660
    }
1661

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

    
1668
        return zooNames;
1669

    
1670
    }
1671

    
1672
    @Override
1673
    public List<TaxonNameBase> findIdenticalTaxonNames(List<String> propertyPaths) {
1674

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

    
1677
        List<TaxonNameBase> zooNames = query.list();
1678

    
1679
        TaxonNameComparator taxComp = new TaxonNameComparator();
1680
        Collections.sort(zooNames, taxComp);
1681

    
1682
        for (TaxonNameBase taxonNameBase: zooNames){
1683
            defaultBeanInitializer.initialize(taxonNameBase, propertyPaths);
1684
        }
1685

    
1686
        return zooNames;
1687
    }
1688

    
1689
    @Override
1690
    public List<TaxonNameBase> findIdenticalNamesNew(List<String> propertyPaths){
1691

    
1692
        //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)
1693
        Query query = getSession().createQuery("Select id from Reference where titleCache like 'Fauna Europaea database'");
1694
        List<String> secRefFauna = query.list();
1695
        query = getSession().createQuery("Select id from Reference where titleCache like 'ERMS'");
1696
        List<String> secRefErms = query.list();
1697
        //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");
1698
        //Get all names of fauna europaea
1699
        query = getSession().createQuery("select zn.nameCache from ZoologicalName zn, TaxonBase tb where tb.name = zn and tb.sec.id = :secRefFauna");
1700
        query.setParameter("secRefFauna", secRefFauna.get(0));
1701
        List<String> namesFauna= query.list();
1702

    
1703
        //Get all names of erms
1704

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

    
1708
        List<String> namesErms = query.list();
1709
        /*TaxonNameComparator comp = new TaxonNameComparator();
1710
        Collections.sort(namesFauna);
1711
        Collections.sort(namesErms);
1712
        */
1713
        List <String> identicalNames = new ArrayList<String>();
1714
        String predecessor = "";
1715

    
1716
        for (String nameFauna: namesFauna){
1717
            if (namesErms.contains(nameFauna)){
1718
                identicalNames.add(nameFauna);
1719
            }
1720
        }
1721

    
1722

    
1723
        query = getSession().createQuery("from ZoologicalName zn where zn.nameCache IN (:identicalNames)");
1724
        query.setParameterList("identicalNames", identicalNames);
1725
        List<TaxonNameBase> result = query.list();
1726
        TaxonNameBase temp = result.get(0);
1727

    
1728
        Iterator<OriginalSourceBase> sources = temp.getSources().iterator();
1729

    
1730
        TaxonNameComparator taxComp = new TaxonNameComparator();
1731
        Collections.sort(result, taxComp);
1732
        defaultBeanInitializer.initializeAll(result, propertyPaths);
1733
        return result;
1734

    
1735
    }
1736

    
1737

    
1738

    
1739
    @Override
1740
    public String getPhylumName(TaxonNameBase name){
1741
        List results = new ArrayList();
1742
        try{
1743
        Query query = getSession().createSQLQuery("select getPhylum("+ name.getId()+");");
1744
        results = query.list();
1745
        }catch(Exception e){
1746
            System.err.println(name.getUuid());
1747
            return null;
1748
        }
1749
        System.err.println("phylum of "+ name.getTitleCache() );
1750
        return (String)results.get(0);
1751
    }
1752

    
1753

    
1754
    @Override
1755
    public long countTaxaByCommonName(String searchString,
1756
            Classification classification, MatchMode matchMode,
1757
            Set<NamedArea> namedAreas) {
1758
        boolean doCount = true;
1759
        Query query = prepareTaxaByCommonName(searchString, classification, matchMode, namedAreas, null, null, doCount, false);
1760
        if (query != null && !query.list().isEmpty()) {
1761
            Object o = query.uniqueResult();
1762
            if(o != null) {
1763
                return (Long)o;
1764
            }
1765
        }
1766
        return 0;
1767
    }
1768

    
1769
    @Override
1770
    public long deleteSynonymRelationships(Synonym synonym, Taxon taxon) {
1771

    
1772
        String hql = "delete SynonymRelationship sr where sr.relatedFrom = :syn ";
1773
        if (taxon != null){
1774
            hql += " and sr.relatedTo = :taxon";
1775
        }
1776
        Session session = this.getSession();
1777
        Query q = session.createQuery(hql);
1778

    
1779
        q.setParameter("syn", synonym);
1780
        if (taxon != null){
1781
            q.setParameter("taxon", taxon);
1782
        }
1783
        long result = q.executeUpdate();
1784

    
1785
        return result;
1786
    }
1787

    
1788

    
1789
    @Override
1790
    public Integer countSynonymRelationships(TaxonBase taxonBase,
1791
            SynonymRelationshipType type, Direction relatedfrom) {
1792
        AuditEvent auditEvent = getAuditEventFromContext();
1793
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1794
            Query query = null;
1795

    
1796
            if(type == null) {
1797
                query = getSession().createQuery("select count(synonymRelationship) from SynonymRelationship synonymRelationship where synonymRelationship."+relatedfrom+" = :relatedSynonym");
1798
            } else {
1799
                query = getSession().createQuery("select count(synonymRelationship) from SynonymRelationship synonymRelationship where synonymRelationship."+relatedfrom+" = :relatedSynonym and synonymRelationship.type = :type");
1800
                query.setParameter("type",type);
1801
            }
1802
            query.setParameter("relatedTaxon", taxonBase);
1803

    
1804
            return ((Long)query.uniqueResult()).intValue();
1805
        } else {
1806
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());
1807
            query.add(AuditEntity.relatedId(relatedfrom.toString()).eq(taxonBase.getId()));
1808
            query.addProjection(AuditEntity.id().count());
1809

    
1810
            if(type != null) {
1811
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1812
            }
1813

    
1814
            return ((Long)query.getSingleResult()).intValue();
1815
        }
1816
    }
1817

    
1818

    
1819
    @Override
1820
    public List<SynonymRelationship> getSynonymRelationships(TaxonBase taxonBase,
1821
            SynonymRelationshipType type, Integer pageSize, Integer pageNumber,
1822
            List<OrderHint> orderHints, List<String> propertyPaths,
1823
            Direction direction) {
1824

    
1825
        AuditEvent auditEvent = getAuditEventFromContext();
1826
        if(auditEvent.equals(AuditEvent.CURRENT_VIEW)) {
1827
            Criteria criteria = getSession().createCriteria(SynonymRelationship.class);
1828

    
1829
            if (direction.equals(Direction.relatedTo)){
1830
                criteria.add(Restrictions.eq("relatedTo", taxonBase));
1831
            }else{
1832
                criteria.add(Restrictions.eq("relatedFrom", taxonBase));
1833
            }
1834
            if(type != null) {
1835
                criteria.add(Restrictions.eq("type", type));
1836
            }
1837

    
1838
            addOrder(criteria,orderHints);
1839

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

    
1849
            List<SynonymRelationship> result = criteria.list();
1850
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1851

    
1852
            return result;
1853
        } else {
1854
            AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(TaxonRelationship.class,auditEvent.getRevisionNumber());
1855

    
1856
            if (direction.equals(Direction.relatedTo)){
1857
                query.add(AuditEntity.relatedId("relatedTo").eq(taxonBase.getId()));
1858
            }else{
1859
                query.add(AuditEntity.relatedId("relatedFrom").eq(taxonBase.getId()));
1860
            }
1861

    
1862
            if(type != null) {
1863
                query.add(AuditEntity.relatedId("type").eq(type.getId()));
1864
            }
1865

    
1866
            if(pageSize != null) {
1867
                query.setMaxResults(pageSize);
1868
                if(pageNumber != null) {
1869
                    query.setFirstResult(pageNumber * pageSize);
1870
                } else {
1871
                    query.setFirstResult(0);
1872
                }
1873
            }
1874

    
1875
            List<SynonymRelationship> result = query.getResultList();
1876
            defaultBeanInitializer.initializeAll(result, propertyPaths);
1877

    
1878
            // Ugly, but for now, there is no way to sort on a related entity property in Envers,
1879
            // and we can't live without this functionality in CATE as it screws up the whole
1880
            // taxon tree thing
1881
            if(orderHints != null && !orderHints.isEmpty()) {
1882
                SortedSet<SynonymRelationship> sortedList = new TreeSet<SynonymRelationship>(new SynonymRelationshipFromTaxonComparator());
1883
                sortedList.addAll(result);
1884
                return new ArrayList<SynonymRelationship>(sortedList);
1885
            }
1886

    
1887
            return result;
1888
        }
1889
    }
1890

    
1891

    
1892
    public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCache(Integer limit, String pattern, boolean isTaxon) {
1893
        String className;
1894
        if (isTaxon){
1895
            className = Taxon.class.getSimpleName();
1896
        } else{
1897
            className = Synonym.class.getSimpleName();
1898
        }
1899
        String queryString;
1900

    
1901
        if(pattern == null){
1902
            queryString = String.format("select uuid, id, titleCache from %s where DTYPE = '%s' ", type.getSimpleName(), className );
1903
       } else{
1904
           queryString = String.format("select uuid, id, titleCache from %s where DTYPE = '%s' and titleCache like :pattern", type.getSimpleName(), className);
1905
       }
1906
        Query query = getSession().createQuery(queryString);
1907
        if (pattern != null){
1908
            pattern = pattern.replace("*", "%");
1909
            pattern = pattern.replace("?", "_");
1910
            pattern = pattern + "%";
1911
            pattern = pattern.replace("?", "_");
1912
            query.setParameter("pattern", pattern);
1913
        }
1914
        if (limit  != null){
1915
            query.setMaxResults(limit);
1916
        }
1917

    
1918
        List<UuidAndTitleCache<TaxonBase>> result = getUuidAndTitleCache(query);
1919

    
1920
        return result;
1921
    }
1922
    @Override
1923
    public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheSynonym(Integer limit, String pattern){
1924

    
1925
        return getUuidAndTitleCache(limit, pattern, false);
1926
    }
1927

    
1928
    @Override
1929
    public List<UuidAndTitleCache<TaxonBase>> getUuidAndTitleCacheTaxon(Integer limit, String pattern){
1930

    
1931
        return getUuidAndTitleCache(limit, pattern, true);
1932
    }
1933

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

    
1936
           boolean doAreaRestriction = areasExpanded.size() > 0;
1937
           String 	doAreaRestrictionSubSelect = "select %s.id from" +
1938
                " Distribution e" +
1939
                " join e.inDescription d" +
1940
                " join d.taxon t" +
1941
                (classification != null ? " join t.taxonNodes as tn " : " ");
1942

    
1943
           String 	doAreaRestrictionMisappliedNameSubSelect = "select %s.id from" +
1944
            " Distribution e" +
1945
            " join e.inDescription d" +
1946
            " join d.taxon t";
1947

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

    
1951
           String doTaxonNameJoin =   " join t.name n ";
1952

    
1953
           String doSynonymNameJoin =  	" join t.synonymRelations sr join sr.relatedFrom s join s.name sn";
1954

    
1955
           String doMisappliedNamesJoin = " left join t.relationsFromThisTaxon as rft" +
1956
                " left join rft.relatedTo as rt" +
1957
                (classification != null ? " left join rt.taxonNodes as tn2" : " ") +
1958
                " left join rt.name as n2" +
1959
                " left join rft.type as rtype";
1960

    
1961
           String doClassificationWhere = " tn.classification = :classification";
1962
           String doClassificationForMisappliedNamesWhere = " tn2 .classification = :classification";
1963

    
1964
           String doAreaRestrictionWhere =  " e.area.uuid in (:namedAreasUuids)";
1965

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

    
1968
           String doRelationshipTypeComparison = " rtype = :rType ";
1969

    
1970
        String taxonSubselect = null;
1971
        String synonymSubselect = null;
1972
        String misappliedSelect = null;
1973

    
1974
        if(classification != null ){
1975
            if (!doIncludeMisappliedNames){
1976
                if(doAreaRestriction){
1977
                    taxonSubselect = String.format(doAreaRestrictionSubSelect, "t") + doTaxonNameJoin +
1978
                    " WHERE " + doAreaRestrictionWhere +
1979
                    " AND " + doClassificationWhere +
1980
                    " AND " + String.format(doSearchFieldWhere, "n");
1981
                    synonymSubselect = String.format(doAreaRestrictionSubSelect, "s") + doSynonymNameJoin +
1982
                    " WHERE " + doAreaRestrictionWhere +
1983
                    " AND " + doClassificationWhere +
1984
                    " AND " + String.format(doSearchFieldWhere, "sn");
1985
                } else {
1986
                    taxonSubselect = String.format(doTaxonSubSelect, "t" )+ doTaxonNameJoin +
1987
                    " WHERE " + doClassificationWhere +
1988
                    " AND " + String.format(doSearchFieldWhere, "n");
1989
                    synonymSubselect = String.format(doTaxonSubSelect, "s" ) + doSynonymNameJoin +
1990
                    " WHERE " + doClassificationWhere +
1991
                    " AND " + String.format(doSearchFieldWhere, "sn");
1992
                }
1993
            }else{ //misappliedNames included
1994
                if(doAreaRestriction){
1995
                    misappliedSelect = String.format(doAreaRestrictionMisappliedNameSubSelect, "t") + doTaxonNameJoin + doMisappliedNamesJoin +
1996
                    " WHERE " + doAreaRestrictionWhere +
1997
                    " AND " + String.format(doSearchFieldWhere, "n") +
1998
                    " AND " + doClassificationForMisappliedNamesWhere +
1999
                    " AND " + doRelationshipTypeComparison;
2000

    
2001
                    taxonSubselect = String.format(doAreaRestrictionSubSelect, "t") + doTaxonNameJoin +
2002
                    " WHERE " + doAreaRestrictionWhere +
2003
                    " AND "+ String.format(doSearchFieldWhere, "n") + " AND "+ doClassificationWhere;
2004

    
2005
                    synonymSubselect = String.format(doAreaRestrictionSubSelect, "s") + doSynonymNameJoin +
2006
                    " WHERE " + doAreaRestrictionWhere +
2007
                    " AND " + doClassificationWhere + " AND " +  String.format(doSearchFieldWhere, "sn");;
2008

    
2009
                } else {
2010
                    misappliedSelect = String.format(doTaxonMisappliedNameSubSelect, "t" ) + doTaxonNameJoin + doMisappliedNamesJoin +
2011
                    " WHERE " + String.format(doSearchFieldWhere, "n") +
2012
                    " AND " + doClassificationForMisappliedNamesWhere +
2013
                    " AND " + doRelationshipTypeComparison;
2014

    
2015
                    taxonSubselect = String.format(doTaxonSubSelect, "t" ) + doTaxonNameJoin +
2016
                    " WHERE " +  String.format(doSearchFieldWhere, "n") +
2017
                    " AND "+ doClassificationWhere;
2018

    
2019
                    synonymSubselect = String.format(doTaxonSubSelect, "s" ) + doSynonymNameJoin +
2020
                    " WHERE " + doClassificationWhere +
2021
                    " AND " +  String.format(doSearchFieldWhere, "sn");
2022

    
2023
                }
2024
            }
2025
        } else {
2026
            if(doAreaRestriction){
2027
                misappliedSelect = String.format(doAreaRestrictionMisappliedNameSubSelect, "t") + doTaxonNameJoin + doMisappliedNamesJoin +
2028
                " WHERE " + doAreaRestrictionWhere +
2029
                " AND " + String.format(doSearchFieldWhere, "n")+
2030
                " AND " + doRelationshipTypeComparison;
2031

    
2032
                taxonSubselect = String.format(doAreaRestrictionSubSelect, "t") + doTaxonNameJoin +
2033
                " WHERE " + doAreaRestrictionWhere +
2034
                " AND " + String.format(doSearchFieldWhere, "n");
2035

    
2036
                synonymSubselect = String.format(doAreaRestrictionSubSelect, "s") + doSynonymNameJoin +
2037
                " WHERE " +   doAreaRestrictionWhere +
2038
                " AND " +  String.format(doSearchFieldWhere, "sn");
2039

    
2040

    
2041
            } else {
2042
                misappliedSelect = String.format(doTaxonMisappliedNameSubSelect, "t" ) + doTaxonNameJoin + doMisappliedNamesJoin + " WHERE " +  String.format(doSearchFieldWhere, "n") + " AND " + doRelationshipTypeComparison;
2043
                taxonSubselect = String.format(doTaxonSubSelect, "t" ) + doTaxonNameJoin + " WHERE " +  String.format(doSearchFieldWhere, "n");
2044
                synonymSubselect = String.format(doTaxonSubSelect, "s" ) + doSynonymNameJoin + " WHERE " +  String.format(doSearchFieldWhere, "sn");
2045

    
2046
            }
2047
        }
2048
        String[] result = {misappliedSelect, taxonSubselect, synonymSubselect};
2049

    
2050
        return result;
2051
    }
2052

    
2053
	@Override
2054
	public List<UuidAndTitleCache<IdentifiableEntity>> getTaxaByCommonNameForEditor(
2055
			String titleSearchStringSqlized, Classification classification,
2056
			MatchMode matchMode, Set namedAreas) {
2057
	    List<Object> resultArray = new ArrayList<Object>();
2058
		Query query = prepareTaxaByCommonName(titleSearchStringSqlized, classification, matchMode, namedAreas, null, null, false, true);
2059
        if (query != null){
2060
            resultArray = query.list();
2061
            List<UuidAndTitleCache<IdentifiableEntity>> returnResult = new ArrayList<UuidAndTitleCache<IdentifiableEntity>>() ;
2062
            Object[] result;
2063
            for(int i = 0; i<resultArray.size();i++){
2064
            	result = (Object[]) resultArray.get(i);
2065
            	returnResult.add(new UuidAndTitleCache(Taxon.class, (UUID) result[0],(Integer)result[1], (String)result[2], new Boolean(result[4].toString()), null));
2066
            }
2067
            return returnResult;
2068
        }
2069

    
2070
		return null;
2071
	}
2072

    
2073

    
2074
	/**
2075
	 * @param
2076
	 * @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)
2077
	 */
2078
	@Override
2079
	public <S extends TaxonBase> int countByIdentifier(Class<S> clazz,
2080
			String identifier, DefinedTerm identifierType, TaxonNode subtreeFilter, MatchMode matchmode) {
2081
		if (subtreeFilter == null){
2082
			return countByIdentifier(clazz, identifier, identifierType, matchmode);
2083
		}
2084

    
2085
		Class<?> clazzParam = clazz == null ? type : clazz;
2086
		checkNotInPriorView("IdentifiableDaoBase.countByIdentifier(T clazz, String identifier, DefinedTerm identifierType, TaxonNode subMatchMode matchmode)");
2087

    
2088
		boolean isTaxon = clazzParam == Taxon.class || clazzParam == TaxonBase.class;
2089
		boolean isSynonym = clazzParam == Synonym.class || clazzParam == TaxonBase.class;
2090

    
2091
		getSession().update(subtreeFilter);  //to avoid LIE when retrieving treeindex
2092
		String filterStr = "'" + subtreeFilter.treeIndex() + "%%'";
2093
		String accTreeJoin = isTaxon? " LEFT JOIN c.taxonNodes tn  " : "";
2094
		String synTreeJoin = isSynonym ? " LEFT JOIN c.synonymRelations sr LEFT  JOIN sr.relatedTo as acc LEFT JOIN acc.taxonNodes synTn  " : "";
2095
		String accWhere = isTaxon ?  "tn.treeIndex like " + filterStr : "(1=0)";
2096
		String synWhere = isSynonym  ?  "synTn.treeIndex like " + filterStr : "(1=0)";
2097

    
2098
		String queryString = "SELECT count(*)  FROM %s as c " +
2099
                " INNER JOIN c.identifiers as ids " +
2100
                accTreeJoin +
2101
                synTreeJoin +
2102
                " WHERE (1=1) " +
2103
                	"  AND ( " + accWhere + " OR " + synWhere + ")";
2104
		queryString = String.format(queryString, clazzParam.getSimpleName());
2105

    
2106
		if (identifier != null){
2107
			if (matchmode == null || matchmode == MatchMode.EXACT){
2108
				queryString += " AND ids.identifier = '"  + identifier + "'";
2109
			}else {
2110
				queryString += " AND ids.identifier LIKE '" + matchmode.queryStringFrom(identifier)  + "'";
2111
			}
2112
		}
2113
		if (identifierType != null){
2114
        	queryString += " AND ids.type = :type";
2115
        }
2116

    
2117
		Query query = getSession().createQuery(queryString);
2118
        if (identifierType != null){
2119
        	query.setEntity("type", identifierType);
2120
        }
2121

    
2122
		Long c = (Long)query.uniqueResult();
2123
        return c.intValue();
2124
	}
2125

    
2126
	@Override
2127
	public <S extends TaxonBase> List<Object[]> findByIdentifier(
2128
			Class<S> clazz, String identifier, DefinedTerm identifierType, TaxonNode subtreeFilter,
2129
			MatchMode matchmode, boolean includeEntity,
2130
			Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
2131

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

    
2135
		boolean isTaxon = clazzParam == Taxon.class || clazzParam == TaxonBase.class;
2136
		boolean isSynonym = clazzParam == Synonym.class || clazzParam == TaxonBase.class;
2137
		getSession().update(subtreeFilter);  //to avoid LIE when retrieving treeindex
2138
		String filterStr = "'" + subtreeFilter.treeIndex() + "%%'";
2139
		String accTreeJoin = isTaxon? " LEFT JOIN c.taxonNodes tn  " : "";
2140
		String synTreeJoin = isSynonym ? " LEFT JOIN c.synonymRelations sr LEFT  JOIN sr.relatedTo as acc LEFT JOIN acc.taxonNodes synTn  " : "";
2141
		String accWhere = isTaxon ?  "tn.treeIndex like " + filterStr : "(1=0)";
2142
		String synWhere = isSynonym  ?  "synTn.treeIndex like " + filterStr : "(1=0)";
2143

    
2144
		String queryString = "SELECT ids.type, ids.identifier, %s " +
2145
				" FROM %s as c " +
2146
                " INNER JOIN c.identifiers as ids " +
2147
                accTreeJoin +
2148
				synTreeJoin +
2149
                " WHERE (1=1) " +
2150
                	" AND ( " + accWhere + " OR " + synWhere + ")";
2151
		queryString = String.format(queryString, (includeEntity ? "c":"c.uuid, c.titleCache") , clazzParam.getSimpleName());
2152

    
2153
		//Matchmode and identifier
2154
		if (identifier != null){
2155
			if (matchmode == null || matchmode == MatchMode.EXACT){
2156
				queryString += " AND ids.identifier = '"  + identifier + "'";
2157
			}else {
2158
				queryString += " AND ids.identifier LIKE '" + matchmode.queryStringFrom(identifier)  + "'";
2159
			}
2160
		}
2161
        if (identifierType != null){
2162
        	queryString += " AND ids.type = :type";
2163
        }
2164
        //order
2165
        queryString +=" ORDER BY ids.type.uuid, ids.identifier, c.uuid ";
2166

    
2167
		Query query = getSession().createQuery(queryString);
2168

    
2169
		//parameters
2170
		if (identifierType != null){
2171
        	query.setEntity("type", identifierType);
2172
        }
2173

    
2174
        //paging
2175
        setPagingParameter(query, pageSize, pageNumber);
2176

    
2177
        List<Object[]> results = query.list();
2178
        //initialize
2179
        if (includeEntity){
2180
        	List<S> entities = new ArrayList<S>();
2181
        	for (Object[] result : results){
2182
        		entities.add((S)result[2]);
2183
        	}
2184
        	defaultBeanInitializer.initializeAll(entities, propertyPaths);
2185
        }
2186
        return results;
2187
	}
2188

    
2189
}
(3-3/4)