Project

General

Profile

Download (21.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

    
10
package eu.etaxonomy.cdm.persistence.dao.hibernate.taxon;
11

    
12
import java.math.BigInteger;
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.Iterator;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Set;
21
import java.util.UUID;
22

    
23
import org.apache.log4j.Logger;
24
import org.hibernate.Criteria;
25
import org.hibernate.Hibernate;
26
import org.hibernate.Query;
27
import org.hibernate.criterion.Projections;
28
import org.hibernate.criterion.Restrictions;
29
import org.springframework.beans.factory.annotation.Autowired;
30
import org.springframework.beans.factory.annotation.Qualifier;
31
import org.springframework.stereotype.Repository;
32

    
33
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
34
import eu.etaxonomy.cdm.model.common.TreeIndex;
35
import eu.etaxonomy.cdm.model.reference.Reference;
36
import eu.etaxonomy.cdm.model.taxon.Classification;
37
import eu.etaxonomy.cdm.model.taxon.Taxon;
38
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
39
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
40
import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
41
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.AnnotatableDaoImpl;
42
import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;
43
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
44
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
45
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
46
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
47

    
48
/**
49
 * @author a.mueller
50
 * @created 16.06.2009
51
 */
52
@Repository
53
@Qualifier("taxonNodeDaoHibernateImpl")
54
public class TaxonNodeDaoHibernateImpl extends AnnotatableDaoImpl<TaxonNode>
55
		implements ITaxonNodeDao {
56
	@SuppressWarnings("unused")
57
	private static final Logger logger = Logger.getLogger(TaxonNodeDaoHibernateImpl.class);
58

    
59
	@Autowired
60
	private ITaxonDao taxonDao;
61
	@Autowired
62
	private IClassificationDao classificationDao;
63

    
64
	public TaxonNodeDaoHibernateImpl() {
65
		super(TaxonNode.class);
66
	}
67
	@Override
68
	public UUID delete(TaxonNode persistentObject, boolean deleteChildren){
69
		Taxon taxon = persistentObject.getTaxon();
70
		taxon = HibernateProxyHelper.deproxy(taxon, Taxon.class);
71

    
72
		/*Session session = this.getSession();
73
		Query query = session.createQuery("from TaxonNode t where t.taxon = :taxon");
74
		query.setParameter("taxon", taxon);
75
		List result = query.list();*/
76
		if (taxon != null){
77
		    Hibernate.initialize(taxon);
78
		    Hibernate.initialize(taxon.getTaxonNodes());
79
			Set<TaxonNode> nodes = taxon.getTaxonNodes();
80
			//Hibernate.initialize(taxon.getTaxonNodes());
81
			for (TaxonNode node:nodes) {
82
			    System.out.println("Number of nodes: " + nodes.size());
83
                node = HibernateProxyHelper.deproxy(node, TaxonNode.class);
84

    
85
			    if (node.equals(persistentObject)){
86
			        if (node.hasChildNodes()){
87
			            Iterator<TaxonNode> childNodes = node.getChildNodes().iterator();
88
			            TaxonNode childNode;
89
			            List<TaxonNode> listForDeletion = new ArrayList<TaxonNode>();
90
	                    while (childNodes.hasNext()){
91
	                        childNode = childNodes.next();
92
	                        listForDeletion.add(childNode);
93
	                        childNodes.remove();
94

    
95
	                    }
96
	                    for (TaxonNode deleteNode:listForDeletion){
97
	                        delete(deleteNode, deleteChildren);
98
	                    }
99
	                }
100

    
101
			        taxon.removeTaxonNode(node, deleteChildren);
102
			        taxonDao.saveOrUpdate(taxon);
103
    				taxon = HibernateProxyHelper.deproxy(taxonDao.findByUuid(taxon.getUuid()), Taxon.class);
104
    				taxonDao.delete(taxon);
105

    
106
			    }
107
			}
108
		}
109

    
110
		UUID result = super.delete(persistentObject);
111

    
112
		return result;
113
	}
114

    
115
	@Override
116
	public List<TaxonNode> getTaxonOfAcceptedTaxaByClassification(Classification classification, Integer start, Integer end) {
117
		int classificationId = classification.getId();
118
		String limit = "";
119
		if(start !=null && end != null){
120
		    limit = "LIMIT "+start+"," +end;
121
		}
122
		//FIXME write test
123
        String queryString = "SELECT DISTINCT nodes.*,taxa.titleCache FROM TaxonNode AS nodes LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id WHERE taxa.DTYPE = 'Taxon' AND nodes.classification_id = " + classificationId + " ORDER BY taxa.titleCache " + limit;
124
        @SuppressWarnings("unchecked")
125
        List<TaxonNode> result  = getSession().createSQLQuery(queryString).addEntity(TaxonNode.class).list();
126

    
127
       return result;
128
	}
129

    
130
    @Override
131
    public int countTaxonOfAcceptedTaxaByClassification(Classification classification){
132
        int classificationId = classification.getId();
133
        //FIXME write test
134
        String queryString = "SELECT DISTINCT COUNT('nodes.*') FROM TaxonNode AS nodes LEFT JOIN TaxonBase AS taxa ON nodes.taxon_id = taxa.id WHERE taxa.DTYPE = 'Taxon' AND nodes.classification_id = " + classificationId;
135
         @SuppressWarnings("unchecked")
136
        List<BigInteger> result = getSession().createSQLQuery(queryString).list();
137
         return result.get(0).intValue ();
138
    }
139

    
140
    @Override
141
    public List<UuidAndTitleCache<TaxonNode>> listChildNodesAsUuidAndTitleCache(UuidAndTitleCache<TaxonNode> parent) {
142
        String queryString = "select tn.uuid, tn.id, tx.titleCache from TaxonNode tn INNER JOIN tn.taxon as tx where tn.parent.id = :parentId";
143
        Query query =  getSession().createQuery(queryString);
144
        query.setParameter("parentId", parent.getId());
145
        List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>();
146

    
147
        @SuppressWarnings("unchecked")
148
        List<Object[]> result = query.list();
149

    
150
        for(Object[] object : result){
151
            list.add(new UuidAndTitleCache<TaxonNode>((UUID) object[0],(Integer) object[1], (String) object[2]));
152
        }
153
        return list;
154
    }
155

    
156
    @Override
157
    public List<UuidAndTitleCache<TaxonNode>> getUuidAndTitleCache(Integer limit, String pattern, UUID classificationUuid) {
158
        String queryString = "select tn.uuid, tn.id, tx.titleCache from TaxonNode tn "
159
        		+ "INNER JOIN tn.taxon as tx "
160
        		+ "INNER JOIN tn.classification as cls "
161
        		+ "WHERE tx.titleCache like :pattern ";
162
        if(classificationUuid!=null){
163
        	queryString += "AND cls.uuid = :classificationUuid";
164
        }
165
        Query query =  getSession().createQuery(queryString);
166

    
167
        query.setParameter("pattern", pattern.toLowerCase()+"%");
168
        query.setParameter("classificationUuid", classificationUuid);
169

    
170
        List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>();
171

    
172
        @SuppressWarnings("unchecked")
173
        List<Object[]> result = query.list();
174

    
175
        for(Object[] object : result){
176
            list.add(new UuidAndTitleCache<TaxonNode>((UUID) object[0],(Integer) object[1], (String) object[2]));
177
        }
178
        return list;
179
    }
180

    
181
    /**
182
     * {@inheritDoc}
183
     */
184
    @Override
185
    public UuidAndTitleCache<TaxonNode> getParentUuidAndTitleCache(UuidAndTitleCache<TaxonNode> child) {
186
        String queryString = "select tn.parent.uuid, tn.parent.id, tn.parent.taxon.titleCache, tn.parent.classification.titleCache "
187
                + " from TaxonNode tn"
188
                + " LEFT OUTER JOIN tn.parent.taxon"
189
                + " where tn.id = :childId";
190
        Query query =  getSession().createQuery(queryString);
191
        query.setParameter("childId", child.getId());
192
        List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>();
193

    
194
        @SuppressWarnings("unchecked")
195
        List<Object[]> result = query.list();
196

    
197
        for(Object[] object : result){
198
            UUID uuid = (UUID) object[0];
199
            Integer id = (Integer) object[1];
200
            String taxonTitleCache = (String) object[2];
201
            String classificationTitleCache = (String) object[3];
202
            if(taxonTitleCache!=null){
203
                list.add(new UuidAndTitleCache<TaxonNode>(uuid,id, taxonTitleCache));
204
            }
205
            else{
206
                list.add(new UuidAndTitleCache<TaxonNode>(uuid,id, classificationTitleCache));
207
            }
208
        }
209
        if(list.size()==1){
210
            return list.iterator().next();
211
        }
212
        return null;
213
    }
214

    
215
    @Override
216
    public List<TaxonNode> listChildrenOf(TaxonNode node, Integer pageSize, Integer pageIndex, List<String> propertyPaths, boolean recursive){
217
    	if (recursive == true){
218
    		Criteria crit = getSession().createCriteria(TaxonNode.class);
219
    		crit.add( Restrictions.like("treeIndex", node.treeIndex()+ "%") );
220
    		if(pageSize != null) {
221
                crit.setMaxResults(pageSize);
222
                if(pageIndex != null) {
223
                    crit.setFirstResult(pageIndex * pageSize);
224
                } else {
225
                    crit.setFirstResult(0);
226
                }
227
            }
228
    		@SuppressWarnings("unchecked")
229
            List<TaxonNode> results = crit.list();
230
    		results.remove(node);
231
    		defaultBeanInitializer.initializeAll(results, propertyPaths);
232
    		return results;
233
    	}else{
234
    		return classificationDao.listChildrenOf(node.getTaxon(), node.getClassification(), pageSize, pageIndex, propertyPaths);
235
    	}
236

    
237
    }
238

    
239
    @Override
240
	public Long countChildrenOf(TaxonNode node, Classification classification,
241
			boolean recursive) {
242

    
243
		if (recursive == true){
244
			Criteria crit = getSession().createCriteria(TaxonNode.class);
245
    		crit.add( Restrictions.like("treeIndex", node.treeIndex()+ "%") );
246
    		crit.setProjection(Projections.rowCount());
247
    		return ((Integer)crit.uniqueResult().hashCode()).longValue();
248
		}else{
249
			return classificationDao.countChildrenOf(node.getTaxon(), classification);
250
		}
251
	}
252
    /**
253
     * {@inheritDoc}
254
     */
255
    @Override
256
    public List<TaxonNodeAgentRelation> listTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,
257
            UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer start, Integer limit, List<String> propertyPaths) {
258

    
259

    
260
        StringBuilder hql = prepareListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, false);
261

    
262
        Query query =  getSession().createQuery(hql.toString());
263

    
264
        if(limit != null) {
265
            query.setMaxResults(limit);
266
            if(start != null) {
267
                query.setFirstResult(start);
268
            }
269
        }
270

    
271
        setParamsForListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, query);
272

    
273
        @SuppressWarnings("unchecked")
274
        List<TaxonNodeAgentRelation> records = query.list();
275

    
276
        if(propertyPaths != null) {
277
            defaultBeanInitializer.initializeAll(records, propertyPaths);
278
        }
279
        return records;
280
    }
281

    
282
    /**
283
     * {@inheritDoc}
284
     */
285
    @Override
286
    public long countTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid, UUID rankUuid, UUID relTypeUuid) {
287

    
288
        StringBuilder hql = prepareListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, true);
289
        Query query =  getSession().createQuery(hql.toString());
290

    
291
        setParamsForListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, query);
292

    
293
        Long count = Long.parseLong(query.uniqueResult().toString());
294

    
295
        return count;
296
    }
297
    /**
298
     * @param taxonUuid
299
     * @param classificationUuid
300
     * @param agentUuid
301
     * @param relTypeUuid TODO
302
     * @param doCount TODO
303
     * @param rankId
304
     *     limit to taxa having this rank, only applies if <code>taxonUuid = null</code>
305
     * @return
306
     */
307
    private StringBuilder prepareListTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid, UUID rankUuid, UUID relTypeUuid, boolean doCount) {
308

    
309
        StringBuilder hql = new StringBuilder();
310

    
311
        String join_fetch_mode = doCount ? "join" : "join fetch";
312

    
313
        if(doCount) {
314
            hql.append("select count(tnar)");
315
        } else {
316
            hql.append("select tnar");
317
        }
318

    
319
        hql.append(" from TaxonNodeAgentRelation as tnar ");
320
        if(taxonUuid != null) {
321
            // taxonUuid is search filter, do not fetch it
322
            hql.append(" join tnar.taxonNode as tn join tn.taxon as t ");
323
        } else {
324
            hql.append(join_fetch_mode).append(" tnar.taxonNode as tn ").append(join_fetch_mode).append(" tn.taxon as t ");
325
            if(rankUuid != null) {
326
                hql.append(" join t.name as n ");
327
            }
328
        }
329
        hql.append(" join tn.classification as c ");
330
        if(agentUuid != null) {
331
            // agentUuid is search filter, do not fetch it
332
//            hql.append(" join tnar.agent as a ");
333
            hql.append(join_fetch_mode).append(" tnar.agent as a ");
334
        } else {
335
            hql.append(join_fetch_mode).append(" tnar.agent as a ");
336
        }
337

    
338
        hql.append(" where 1 = 1 ");
339

    
340
        if(relTypeUuid != null) {
341
            hql.append(" and tnar.type.uuid = :relTypeUuid ");
342
        }
343

    
344
        if(taxonUuid != null) {
345
            hql.append(" and t.uuid = :taxonUuid ");
346
        } else {
347
            if(rankUuid != null) {
348
                hql.append(" and n.rank.uuid = :rankUuid ");
349
            }
350
        }
351
        if(classificationUuid != null) {
352
            hql.append(" and c.uuid = :classificationUuid ");
353
        }
354
        if(agentUuid != null) {
355
            hql.append(" and a.uuid = :agentUuid ");
356
        }
357

    
358
        hql.append(" order by a.titleCache");
359
        return hql;
360
    }
361
    /**
362
     * @param taxonUuid
363
     * @param classificationUuid
364
     * @param agentUuid
365
     * @param relTypeUuid TODO
366
     * @param query
367
     * @param rankId TODO
368
     */
369
    private void setParamsForListTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid,
370
            UUID rankUuid, UUID relTypeUuid, Query query) {
371

    
372
        if(taxonUuid != null) {
373
            query.setParameter("taxonUuid", taxonUuid);
374
        } else {
375
            if(rankUuid != null) {
376
                query.setParameter("rankUuid", rankUuid);
377
            }
378
        }
379
        if(classificationUuid != null) {
380
            query.setParameter("classificationUuid", classificationUuid);
381
        }
382
        if(agentUuid != null) {
383
            query.setParameter("agentUuid", agentUuid);
384
        }
385
        if(relTypeUuid != null) {
386
            query.setParameter("relTypeUuid", relTypeUuid);
387
        }
388
    }
389

    
390
    @Override
391
    public Map<TreeIndex, Integer> rankOrderIndexForTreeIndex(List<TreeIndex> treeIndexes,
392
            Integer minRankOrderIndex,
393
            Integer maxRankOrderIndex) {
394

    
395
        Map<TreeIndex, Integer> result = new HashMap<>();
396
        if (treeIndexes == null || treeIndexes.isEmpty()){
397
            return result;
398
        }
399

    
400
        String hql = " SELECT tn.treeIndex, r.orderIndex "
401
                + " FROM TaxonNode tn JOIN tn.taxon t JOIN t.name n JOIN n.rank r "
402
                + " WHERE tn.treeIndex IN (:treeIndexes) ";
403
        if (minRankOrderIndex != null){
404
            hql += " AND r.orderIndex <= :minOrderIndex";
405
        }
406
        if (maxRankOrderIndex != null){
407
            hql += " AND r.orderIndex >= :maxOrderIndex";
408
        }
409

    
410
        Query query =  getSession().createQuery(hql);
411
        query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));
412
        if (minRankOrderIndex != null){
413
            query.setParameter("minOrderIndex", minRankOrderIndex);
414
        }
415
        if (maxRankOrderIndex != null){
416
            query.setParameter("maxOrderIndex", maxRankOrderIndex);
417
        }
418

    
419
        @SuppressWarnings("unchecked")
420
        List<Object[]> list = query.list();
421
        for (Object[] o : list){
422
            result.put(TreeIndex.NewInstance((String)o[0]), (Integer)o[1]);
423
        }
424
        return result;
425
    }
426

    
427
    @Override
428
    public Map<TreeIndex, UuidAndTitleCache<?>> taxonUuidsForTreeIndexes(Collection<TreeIndex> treeIndexes) {
429
        Map<TreeIndex, UuidAndTitleCache<?>> result = new HashMap<>();
430
        if (treeIndexes == null || treeIndexes.isEmpty()){
431
            return result;
432
        }
433

    
434
        String hql = " SELECT tn.treeIndex, t.uuid, tnb.titleCache "
435
                + " FROM TaxonNode tn JOIN tn.taxon t Join t.name tnb "
436
                + " WHERE tn.treeIndex IN (:treeIndexes) ";
437
        Query query =  getSession().createQuery(hql);
438
        query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));
439

    
440
        @SuppressWarnings("unchecked")
441
        List<Object[]> list = query.list();
442
        for (Object[] o : list){
443
            result.put(TreeIndex.NewInstance((String)o[0]), new UuidAndTitleCache<>((UUID)o[1], null, (String)o[2]));
444
        }
445
        return result;
446
    }
447

    
448

    
449
    /**
450
     * {@inheritDoc}
451
     */
452
    //#3465
453
    @Override
454
    public Set<TaxonBase> setSecundumForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, Reference newSec, boolean overwriteExisting, boolean includeSharedTaxa, boolean emptyDetail) {
455
        //for some reason this does not work, maybe because the listeners are not activated,
456
        //but also the first taxon for some reason does not get updated in terms of secundum, but only by the udpate listener
457
//        String where = "SELECT t.id FROM TaxonNode tn JOIN tn.taxon t " +
458
//                " WHERE tn.treeIndex like '%s%%' ORDER BY t.id";
459
//        where = String.format(where, subTreeIndex.toString());
460
//        Query query1 = getSession().createQuery(where);
461
//        List l = query1.list();
462
//
463
//        String hql = "UPDATE Taxon SET sec = :newSec, publish=false WHERE id IN (" + where + ")";
464
//        Query query = getSession().createQuery(hql);
465
//        query.setParameter("newSec", newSec);
466
//        int n = query.executeUpdate();
467

    
468
        String queryStr = acceptedForSubtreeQueryStr(includeSharedTaxa, subTreeIndex);
469
        if (!overwriteExisting){
470
            queryStr += " AND t.sec IS NULL ";
471
        }
472
        return setSecundum(newSec, emptyDetail, queryStr);
473

    
474
    }
475

    
476
    @Override
477
    public Set<TaxonBase> setSecundumForSubtreeSynonyms(TreeIndex subTreeIndex, Reference newSec, boolean overwriteExisting, boolean includeSharedTaxa, boolean emptyDetail) {
478

    
479
        String queryStr = synonymForSubtreeQueryStr(includeSharedTaxa, subTreeIndex);
480
        if (!overwriteExisting){
481
            queryStr += " AND syn.sec IS NULL ";
482
        }
483
        return setSecundum(newSec, emptyDetail, queryStr);
484
    }
485
    /**
486
     * @param newSec
487
     * @param emptyDetail
488
     * @param queryStr
489
     * @return
490
     */
491
    private <T extends TaxonBase<?>> Set<T> setSecundum(Reference newSec, boolean emptyDetail, String queryStr) {
492
        Query query = getSession().createQuery(queryStr);
493
        @SuppressWarnings("unchecked")
494
        List<T> synonymList = query.list();
495
        MergeResult mergeResult;
496
        Set<T> result = new HashSet<>();
497
        for (T taxonBase : synonymList){
498
            taxonBase = (T) taxonDao.load(taxonBase.getUuid());
499

    
500
            taxonBase.setSec(newSec);
501
            if (emptyDetail){
502
                taxonBase.setSecMicroReference(null);
503
            }
504
           result.add(taxonBase);
505

    
506
        }
507
      return result;
508
    }
509

    
510

    
511
    /**
512
     * {@inheritDoc}
513
     */
514
    @Override
515
    public Set<TaxonBase> setPublishForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, boolean publish,
516
            boolean includeSharedTaxa) {
517
        String queryStr = acceptedForSubtreeQueryStr(includeSharedTaxa, subTreeIndex);
518
        return setPublish(publish, queryStr);
519
    }
520

    
521
    /**
522
     * {@inheritDoc}
523
     */
524
    @Override
525
    public Set<TaxonBase> setPublishForSubtreeSynonyms(TreeIndex subTreeIndex, boolean publish,
526
            boolean includeSharedTaxa) {
527
        String queryStr = synonymForSubtreeQueryStr(includeSharedTaxa, subTreeIndex);
528
        return setPublish(publish, queryStr);
529
    }
530

    
531
    /**
532
     * @param publish
533
     * @param queryStr
534
     * @return
535
     */
536
    private <T extends TaxonBase<?>> Set<T> setPublish(boolean publish, String queryStr) {
537
        Query query = getSession().createQuery(queryStr);
538
        @SuppressWarnings("unchecked")
539
        List<T> taxonList = query.list();
540
        Set<T> result = new HashSet<>();
541
        for (T taxon : taxonList){
542
            taxon = (T)taxonDao.load(taxon.getUuid());
543
            taxon.setPublish(publish);
544
            result.add(taxon);
545
        }
546
        return result;
547
    }
548

    
549

    
550
    /**
551
     * @param includeSharedTaxa
552
     * @param subTreeIndex
553
     * @return
554
     */
555
    private String synonymForSubtreeQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex) {
556
        String queryStr = "SELECT syn "
557
                + " FROM TaxonNode tn JOIN tn.taxon t JOIN t.synonyms syn"
558
                + " WHERE tn.treeIndex like '%s%%' ";
559
        if (!includeSharedTaxa){
560
            queryStr += " AND t.taxonNodes.size <= 1  ";
561
        }
562
        queryStr = String.format(queryStr, subTreeIndex.toString());
563

    
564
        return queryStr;
565
    }
566

    
567
    private String acceptedForSubtreeQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex) {
568
        String queryStr = "SELECT t "
569
                + " FROM TaxonNode tn JOIN tn.taxon t "
570
                + " WHERE tn.treeIndex like '%s%%' ";
571
        if (!includeSharedTaxa){
572
            queryStr += " AND t.taxonNodes.size <= 1  ";
573
        }
574
        queryStr = String.format(queryStr, subTreeIndex.toString());
575

    
576
        return queryStr;
577
    }
578

    
579

    
580
}
(4-4/5)