Project

General

Profile

Download (30.5 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.Collections;
16
import java.util.HashMap;
17
import java.util.HashSet;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.Map;
21
import java.util.Set;
22
import java.util.UUID;
23

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

    
34
import eu.etaxonomy.cdm.common.CdmUtils;
35
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
36
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
37
import eu.etaxonomy.cdm.model.common.CdmBase;
38
import eu.etaxonomy.cdm.model.common.TreeIndex;
39
import eu.etaxonomy.cdm.model.reference.Reference;
40
import eu.etaxonomy.cdm.model.taxon.Classification;
41
import eu.etaxonomy.cdm.model.taxon.Taxon;
42
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
43
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
44
import eu.etaxonomy.cdm.model.taxon.TaxonNodeAgentRelation;
45
import eu.etaxonomy.cdm.model.taxon.UuidAndTitleCacheTaxonComparator;
46
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.AnnotatableDaoImpl;
47
import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;
48
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonDao;
49
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
50
import eu.etaxonomy.cdm.persistence.dto.TaxonNodeDto;
51
import eu.etaxonomy.cdm.persistence.dto.UuidAndTitleCache;
52

    
53
/**
54
 * @author a.mueller
55
 * @since 16.06.2009
56
 */
57
@Repository
58
@Qualifier("taxonNodeDaoHibernateImpl")
59
public class TaxonNodeDaoHibernateImpl extends AnnotatableDaoImpl<TaxonNode>
60
		implements ITaxonNodeDao {
61
	@SuppressWarnings("unused")
62
	private static final Logger logger = Logger.getLogger(TaxonNodeDaoHibernateImpl.class);
63

    
64
	@Autowired
65
	private ITaxonDao taxonDao;
66
	@Autowired
67
	private IClassificationDao classificationDao;
68

    
69
	public TaxonNodeDaoHibernateImpl() {
70
		super(TaxonNode.class);
71
	}
72
	@Override
73
	public UUID delete(TaxonNode persistentObject, boolean deleteChildren){
74
		Taxon taxon = persistentObject.getTaxon();
75
		taxon = HibernateProxyHelper.deproxy(taxon, Taxon.class);
76

    
77
		/*Session session = this.getSession();
78
		Query query = session.createQuery("from TaxonNode t where t.taxon = :taxon");
79
		query.setParameter("taxon", taxon);
80
		List result = query.list();*/
81
		if (taxon != null){
82
		    Hibernate.initialize(taxon);
83
		    Hibernate.initialize(taxon.getTaxonNodes());
84
			Set<TaxonNode> nodes = taxon.getTaxonNodes();
85
			//Hibernate.initialize(taxon.getTaxonNodes());
86
			for (TaxonNode node:nodes) {
87
			    node = HibernateProxyHelper.deproxy(node, TaxonNode.class);
88

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

    
99
	                    }
100
	                    for (TaxonNode deleteNode:listForDeletion){
101
	                        delete(deleteNode, deleteChildren);
102
	                    }
103
	                }
104

    
105
			        taxon.removeTaxonNode(node, deleteChildren);
106
			        taxonDao.saveOrUpdate(taxon);
107
    				taxon = HibernateProxyHelper.deproxy(taxonDao.findByUuid(taxon.getUuid()), Taxon.class);
108
    				taxonDao.delete(taxon);
109

    
110
			    }
111
			}
112
		}
113

    
114
		UUID result = super.delete(persistentObject);
115

    
116
		return result;
117
	}
118

    
119
	@Override
120
	public List<TaxonNode> getTaxonOfAcceptedTaxaByClassification(Classification classification, Integer start, Integer end) {
121
		int classificationId = classification.getId();
122
		String limit = "";
123
		if(start !=null && end != null){
124
		    limit = "LIMIT "+start+"," +end;
125
		}
126
		//FIXME write test
127
        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;
128
        @SuppressWarnings("unchecked")
129
        List<TaxonNode> result  = getSession().createSQLQuery(queryString).addEntity(TaxonNode.class).list();
130

    
131
       return result;
132
	}
133

    
134
    @Override
135
    public int countTaxonOfAcceptedTaxaByClassification(Classification classification){
136
        int classificationId = classification.getId();
137
        //FIXME write test
138
        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;
139
         @SuppressWarnings("unchecked")
140
        List<BigInteger> result = getSession().createSQLQuery(queryString).list();
141
         return result.get(0).intValue ();
142
    }
143

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

    
151
        @SuppressWarnings("unchecked")
152
        List<Object[]> result = query.list();
153

    
154
        for(Object[] object : result){
155
            list.add(new UuidAndTitleCache<TaxonNode>((UUID) object[0],(Integer) object[1], (String) object[2]));
156
        }
157
        return list;
158
    }
159

    
160
    @Override
161
    public List<TaxonNodeDto> listChildNodesAsTaxonNodeDto(UuidAndTitleCache<TaxonNode> parent) {
162
        String queryString = "select tn from TaxonNode tn INNER JOIN tn.taxon as tx where tn.parent.uuid = :parentId";
163
        Query query =  getSession().createQuery(queryString);
164
        query.setParameter("parentId", parent.getUuid());
165
        List<TaxonNodeDto> list = new ArrayList<>();
166

    
167
        @SuppressWarnings("unchecked")
168
        List<TaxonNode> result = query.list();
169

    
170
        for(TaxonNode object : result){
171
            list.add(new TaxonNodeDto(object));
172
        }
173
        return list;
174
    }
175
    @Override
176
    public List<UuidAndTitleCache<TaxonNode>> getUuidAndTitleCache(Integer limit, String pattern, UUID classificationUuid) {
177
        String queryString = "select tn.uuid, tn.id, tx.titleCache, tx.name.rank from TaxonNode tn "
178
        		+ "INNER JOIN tn.taxon as tx "
179
        		+ "INNER JOIN tn.classification as cls "
180
        		+ "WHERE tx.titleCache like :pattern ";
181
        if(classificationUuid!=null){
182
        	queryString += "AND cls.uuid = :classificationUuid";
183
        }
184
        Query query =  getSession().createQuery(queryString);
185

    
186
        query.setParameter("pattern", pattern.toLowerCase()+"%");
187
        query.setParameter("classificationUuid", classificationUuid);
188

    
189
        List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>();
190

    
191
        @SuppressWarnings("unchecked")
192
        List<Object[]> result = query.list();
193

    
194
        if (result != null){
195
            Collections.sort(result, new UuidAndTitleCacheTaxonComparator());
196
        }
197
        for(Object[] object : result){
198
            list.add(new UuidAndTitleCache<TaxonNode>((UUID) object[0],(Integer) object[1], (String) object[2]));
199
        }
200
        return list;
201
    }
202

    
203
    /**
204
     * {@inheritDoc}
205
     */
206
    @Override
207
    public UuidAndTitleCache<TaxonNode> getParentUuidAndTitleCache(UuidAndTitleCache<TaxonNode> child) {
208
        String queryString = "select tn.parent.uuid, tn.parent.id, tn.parent.taxon.titleCache, tn.parent.classification.titleCache "
209
                + " from TaxonNode tn"
210
                + " LEFT OUTER JOIN tn.parent.taxon"
211
                + " where tn.id = :childId";
212
        Query query =  getSession().createQuery(queryString);
213
        query.setParameter("childId", child.getId());
214
        List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<>();
215

    
216
        @SuppressWarnings("unchecked")
217
        List<Object[]> result = query.list();
218

    
219
        for(Object[] object : result){
220
            UUID uuid = (UUID) object[0];
221
            Integer id = (Integer) object[1];
222
            String taxonTitleCache = (String) object[2];
223
            String classificationTitleCache = (String) object[3];
224
            if(taxonTitleCache!=null){
225
                list.add(new UuidAndTitleCache<TaxonNode>(uuid,id, taxonTitleCache));
226
            }
227
            else{
228
                list.add(new UuidAndTitleCache<TaxonNode>(uuid,id, classificationTitleCache));
229
            }
230
        }
231
        if(list.size()==1){
232
            return list.iterator().next();
233
        }
234
        return null;
235
    }
236

    
237
    @Override
238
    public List<TaxonNode> listChildrenOf(TaxonNode node, Integer pageSize, Integer pageIndex, List<String> propertyPaths, boolean recursive){
239
    	if (recursive == true){
240
    		Criteria crit = getSession().createCriteria(TaxonNode.class);
241
    		crit.add( Restrictions.like("treeIndex", node.treeIndex()+ "%") );
242
    		if(pageSize != null) {
243
                crit.setMaxResults(pageSize);
244
                if(pageIndex != null) {
245
                    crit.setFirstResult(pageIndex * pageSize);
246
                } else {
247
                    crit.setFirstResult(0);
248
                }
249
            }
250
    		@SuppressWarnings("unchecked")
251
            List<TaxonNode> results = crit.list();
252
    		results.remove(node);
253
    		defaultBeanInitializer.initializeAll(results, propertyPaths);
254
    		return results;
255
    	}else{
256
    		return classificationDao.listChildrenOf(node.getTaxon(), node.getClassification(), pageSize, pageIndex, propertyPaths);
257
    	}
258

    
259
    }
260

    
261
    @Override
262
	public Long countChildrenOf(TaxonNode node, Classification classification,
263
			boolean recursive) {
264

    
265
		if (recursive == true){
266
			Criteria crit = getSession().createCriteria(TaxonNode.class);
267
    		crit.add( Restrictions.like("treeIndex", node.treeIndex()+ "%") );
268
    		crit.setProjection(Projections.rowCount());
269
    		return ((Integer)crit.uniqueResult().hashCode()).longValue();
270
		}else{
271
			return classificationDao.countChildrenOf(node.getTaxon(), classification);
272
		}
273
	}
274
    /**
275
     * {@inheritDoc}
276
     */
277
    @Override
278
    public List<TaxonNodeAgentRelation> listTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid,
279
            UUID agentUuid, UUID rankUuid, UUID relTypeUuid, Integer start, Integer limit, List<String> propertyPaths) {
280

    
281

    
282
        StringBuilder hql = prepareListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, false);
283

    
284
        Query query =  getSession().createQuery(hql.toString());
285

    
286
        if(limit != null) {
287
            query.setMaxResults(limit);
288
            if(start != null) {
289
                query.setFirstResult(start);
290
            }
291
        }
292

    
293
        setParamsForListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, query);
294

    
295
        @SuppressWarnings("unchecked")
296
        List<TaxonNodeAgentRelation> records = query.list();
297

    
298
        if(propertyPaths != null) {
299
            defaultBeanInitializer.initializeAll(records, propertyPaths);
300
        }
301
        return records;
302
    }
303

    
304
    /**
305
     * {@inheritDoc}
306
     */
307
    @Override
308
    public long countTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid, UUID rankUuid, UUID relTypeUuid) {
309

    
310
        StringBuilder hql = prepareListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, true);
311
        Query query =  getSession().createQuery(hql.toString());
312

    
313
        setParamsForListTaxonNodeAgentRelations(taxonUuid, classificationUuid, agentUuid, rankUuid, relTypeUuid, query);
314

    
315
        Long count = Long.parseLong(query.uniqueResult().toString());
316

    
317
        return count;
318
    }
319
    /**
320
     * @param taxonUuid
321
     * @param classificationUuid
322
     * @param agentUuid
323
     * @param relTypeUuid TODO
324
     * @param doCount TODO
325
     * @param rankId
326
     *     limit to taxa having this rank, only applies if <code>taxonUuid = null</code>
327
     * @return
328
     */
329
    private StringBuilder prepareListTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid, UUID rankUuid, UUID relTypeUuid, boolean doCount) {
330

    
331
        StringBuilder hql = new StringBuilder();
332

    
333
        String join_fetch_mode = doCount ? "join" : "join fetch";
334

    
335
        if(doCount) {
336
            hql.append("select count(tnar)");
337
        } else {
338
            hql.append("select tnar");
339
        }
340

    
341
        hql.append(" from TaxonNodeAgentRelation as tnar ");
342
        if(taxonUuid != null) {
343
            // taxonUuid is search filter, do not fetch it
344
            hql.append(" join tnar.taxonNode as tn join tn.taxon as t ");
345
        } else {
346
            hql.append(join_fetch_mode).append(" tnar.taxonNode as tn ").append(join_fetch_mode).append(" tn.taxon as t ");
347
            if(rankUuid != null) {
348
                hql.append(" join t.name as n ");
349
            }
350
        }
351
        hql.append(" join tn.classification as c ");
352
        if(agentUuid != null) {
353
            // agentUuid is search filter, do not fetch it
354
//            hql.append(" join tnar.agent as a ");
355
            hql.append(join_fetch_mode).append(" tnar.agent as a ");
356
        } else {
357
            hql.append(join_fetch_mode).append(" tnar.agent as a ");
358
        }
359

    
360
        hql.append(" where 1 = 1 ");
361

    
362
        if(relTypeUuid != null) {
363
            hql.append(" and tnar.type.uuid = :relTypeUuid ");
364
        }
365

    
366
        if(taxonUuid != null) {
367
            hql.append(" and t.uuid = :taxonUuid ");
368
        } else {
369
            if(rankUuid != null) {
370
                hql.append(" and n.rank.uuid = :rankUuid ");
371
            }
372
        }
373
        if(classificationUuid != null) {
374
            hql.append(" and c.uuid = :classificationUuid ");
375
        }
376
        if(agentUuid != null) {
377
            hql.append(" and a.uuid = :agentUuid ");
378
        }
379

    
380
        hql.append(" order by a.titleCache");
381
        return hql;
382
    }
383
    /**
384
     * @param taxonUuid
385
     * @param classificationUuid
386
     * @param agentUuid
387
     * @param relTypeUuid TODO
388
     * @param query
389
     * @param rankId TODO
390
     */
391
    private void setParamsForListTaxonNodeAgentRelations(UUID taxonUuid, UUID classificationUuid, UUID agentUuid,
392
            UUID rankUuid, UUID relTypeUuid, Query query) {
393

    
394
        if(taxonUuid != null) {
395
            query.setParameter("taxonUuid", taxonUuid);
396
        } else {
397
            if(rankUuid != null) {
398
                query.setParameter("rankUuid", rankUuid);
399
            }
400
        }
401
        if(classificationUuid != null) {
402
            query.setParameter("classificationUuid", classificationUuid);
403
        }
404
        if(agentUuid != null) {
405
            query.setParameter("agentUuid", agentUuid);
406
        }
407
        if(relTypeUuid != null) {
408
            query.setParameter("relTypeUuid", relTypeUuid);
409
        }
410
    }
411

    
412
    @Override
413
    public Map<TreeIndex, Integer> rankOrderIndexForTreeIndex(List<TreeIndex> treeIndexes,
414
            Integer minRankOrderIndex,
415
            Integer maxRankOrderIndex) {
416

    
417
        Map<TreeIndex, Integer> result = new HashMap<>();
418
        if (treeIndexes == null || treeIndexes.isEmpty()){
419
            return result;
420
        }
421

    
422
        String hql = " SELECT tn.treeIndex, r.orderIndex "
423
                + " FROM TaxonNode tn JOIN tn.taxon t JOIN t.name n JOIN n.rank r "
424
                + " WHERE tn.treeIndex IN (:treeIndexes) ";
425
        if (minRankOrderIndex != null){
426
            hql += " AND r.orderIndex <= :minOrderIndex";
427
        }
428
        if (maxRankOrderIndex != null){
429
            hql += " AND r.orderIndex >= :maxOrderIndex";
430
        }
431

    
432
        Query query =  getSession().createQuery(hql);
433
        query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));
434
        if (minRankOrderIndex != null){
435
            query.setParameter("minOrderIndex", minRankOrderIndex);
436
        }
437
        if (maxRankOrderIndex != null){
438
            query.setParameter("maxOrderIndex", maxRankOrderIndex);
439
        }
440

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

    
449
    @Override
450
    public Map<TreeIndex, UuidAndTitleCache<?>> taxonUuidsForTreeIndexes(Collection<TreeIndex> treeIndexes) {
451
        Map<TreeIndex, UuidAndTitleCache<?>> result = new HashMap<>();
452
        if (treeIndexes == null || treeIndexes.isEmpty()){
453
            return result;
454
        }
455

    
456
        String hql = " SELECT tn.treeIndex, t.uuid, tnb.titleCache "
457
                + " FROM TaxonNode tn JOIN tn.taxon t Join t.name tnb "
458
                + " WHERE tn.treeIndex IN (:treeIndexes) ";
459
        Query query =  getSession().createQuery(hql);
460
        query.setParameterList("treeIndexes", TreeIndex.toString(treeIndexes));
461

    
462
        @SuppressWarnings("unchecked")
463
        List<Object[]> list = query.list();
464
        for (Object[] o : list){
465
            result.put(TreeIndex.NewInstance((String)o[0]), new UuidAndTitleCache<>((UUID)o[1], null, (String)o[2]));
466
        }
467
        return result;
468
    }
469

    
470
    /**
471
     * {@inheritDoc}
472
     */
473
    @Override
474
    public int countSecundumForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, Reference newSec,
475
            boolean overwriteExisting, boolean includeSharedTaxa, boolean emptySecundumDetail) {
476
        String queryStr = acceptedForSubtreeQueryStr(includeSharedTaxa, subTreeIndex, SelectMode.COUNT);
477
        if (!overwriteExisting){
478
            queryStr += " AND t.sec IS NULL ";
479
        }
480
        return countResult(queryStr);
481
    }
482
    /**
483
     * @param queryStr
484
     * @return
485
     */
486
    protected int countResult(String queryStr) {
487
        Query query = getSession().createQuery(queryStr);
488
        return ((Long)query.uniqueResult()).intValue();
489
    }
490
    /**
491
     * {@inheritDoc}
492
     */
493
    @Override
494
    public int countSecundumForSubtreeSynonyms(TreeIndex subTreeIndex, Reference newSec,
495
            boolean overwriteExisting, boolean includeSharedTaxa, boolean emptySecundumDetail) {
496
        String queryStr = synonymForSubtreeQueryStr(includeSharedTaxa, subTreeIndex, SelectMode.COUNT);
497
        if (!overwriteExisting){
498
            queryStr += " AND syn.sec IS NULL ";
499
        }
500
        return countResult(queryStr);
501
    }
502

    
503

    
504
    /**
505
     * {@inheritDoc}
506
     */
507
    //#3465
508
    @Override
509
    public Set<TaxonBase> setSecundumForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, Reference newSec,
510
            boolean overwriteExisting, boolean includeSharedTaxa, boolean emptyDetail, IProgressMonitor monitor) {
511
        //for some reason this does not work, maybe because the listeners are not activated,
512
        //but also the first taxon for some reason does not get updated in terms of secundum, but only by the update listener
513
//        String where = "SELECT t.id FROM TaxonNode tn JOIN tn.taxon t " +
514
//                " WHERE tn.treeIndex like '%s%%' ORDER BY t.id";
515
//        where = String.format(where, subTreeIndex.toString());
516
//        Query query1 = getSession().createQuery(where);
517
//        List l = query1.list();
518
//
519
//        String hql = "UPDATE Taxon SET sec = :newSec, publish=false WHERE id IN (" + where + ")";
520
//        Query query = getSession().createQuery(hql);
521
//        query.setParameter("newSec", newSec);
522
//        int n = query.executeUpdate();
523

    
524
        String queryStr = acceptedForSubtreeQueryStr(includeSharedTaxa, subTreeIndex, SelectMode.ID);
525
        if (!overwriteExisting){
526
            queryStr += " AND t.sec IS NULL ";
527
        }
528
        return setSecundum(newSec, emptyDetail, queryStr, monitor);
529

    
530
    }
531

    
532
    @Override
533
    public Set<TaxonBase> setSecundumForSubtreeSynonyms(TreeIndex subTreeIndex, Reference newSec,
534
            boolean overwriteExisting, boolean includeSharedTaxa, boolean emptyDetail, IProgressMonitor monitor) {
535

    
536
        String queryStr = synonymForSubtreeQueryStr(includeSharedTaxa, subTreeIndex, SelectMode.ID);
537
        if (!overwriteExisting){
538
            queryStr += " AND syn.sec IS NULL ";
539
        }
540
        return setSecundum(newSec, emptyDetail, queryStr, monitor);
541
    }
542
    /**
543
     * @param newSec
544
     * @param emptyDetail
545
     * @param queryStr
546
     * @param monitor
547
     * @return
548
     */
549
    @SuppressWarnings("unchecked")
550
    private <T extends TaxonBase<?>> Set<T> setSecundum(Reference newSec, boolean emptyDetail, String queryStr, IProgressMonitor monitor) {
551
        Set<T> result = new HashSet<>();
552
        Query query = getSession().createQuery(queryStr);
553
        List<List<Integer>> partitionList = splitIdList(query.list(), DEFAULT_PARTITION_SIZE);
554
        for (List<Integer> taxonIdList : partitionList){
555
            List<TaxonBase> taxonList = taxonDao.loadList(taxonIdList, null);
556
            for (TaxonBase taxonBase : taxonList){
557
                if (taxonBase != null){
558
                    taxonBase = taxonDao.load(taxonBase.getUuid());
559
                    taxonBase.setSec(newSec);
560
                    if (emptyDetail){
561
                        taxonBase.setSecMicroReference(null);
562
                    }
563
                    result.add((T)CdmBase.deproxy(taxonBase));
564
                    monitor.worked(1);
565
                    if (monitor.isCanceled()){
566
                        return result;
567
                    }
568
                }
569
            }
570
        }
571
        return result;
572
    }
573

    
574
    private List<List<Integer>> splitIdList(List<Integer> idList, Integer size){
575
        List<List<Integer>> result = new ArrayList<>();
576
        for (int i = 0; (i*size)<idList.size(); i++) {
577
            int upper = Math.min((i+1)*size, idList.size());
578
            result.add(idList.subList(i*size, upper));
579
        }
580
        return result;
581
    }
582

    
583
    /**
584
     * {@inheritDoc}
585
     */
586
    @Override
587
    public int countPublishForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, boolean publish, boolean includeSharedTaxa) {
588
        String queryStr = acceptedForSubtreeQueryStr(includeSharedTaxa, subTreeIndex, SelectMode.COUNT);
589
        queryStr += " AND t.publish != :publish ";
590
        Query query = getSession().createQuery(queryStr);
591
        query.setBoolean("publish", publish);
592
        return ((Long)query.uniqueResult()).intValue();
593
//        return countResult(queryStr);
594
    }
595
    /**
596
     * {@inheritDoc}
597
     */
598
    @Override
599
    public int countPublishForSubtreeSynonyms(TreeIndex subTreeIndex, boolean publish, boolean includeSharedTaxa) {
600
        String queryStr = synonymForSubtreeQueryStr(includeSharedTaxa, subTreeIndex, SelectMode.COUNT);
601
        queryStr += " AND syn.publish != :publish ";
602
        Query query = getSession().createQuery(queryStr);
603
        query.setBoolean("publish", publish);
604
        return ((Long)query.uniqueResult()).intValue();
605
//      return countResult(queryStr);
606
    }
607
    /**
608
     * {@inheritDoc}
609
     */
610
    @Override
611
    public Set<TaxonBase> setPublishForSubtreeAcceptedTaxa(TreeIndex subTreeIndex, boolean publish,
612
            boolean includeSharedTaxa, IProgressMonitor monitor) {
613
        String queryStr = acceptedForSubtreeQueryStr(includeSharedTaxa, subTreeIndex, SelectMode.ID);
614
        queryStr += " AND t.publish != :publish ";
615
        return setPublish(publish, queryStr, monitor);
616
    }
617

    
618
    /**
619
     * {@inheritDoc}
620
     */
621
    @Override
622
    public Set<TaxonBase> setPublishForSubtreeSynonyms(TreeIndex subTreeIndex, boolean publish,
623
            boolean includeSharedTaxa, IProgressMonitor monitor) {
624
        String queryStr = synonymForSubtreeQueryStr(includeSharedTaxa, subTreeIndex, SelectMode.ID);
625
        queryStr += " AND syn.publish != :publish ";
626
        return setPublish(publish, queryStr, monitor);
627
    }
628

    
629
    private static final int DEFAULT_PARTITION_SIZE = 100;
630
    /**
631
     * @param publish
632
     * @param queryStr
633
     * @return
634
     */
635
    private <T extends TaxonBase<?>> Set<T> setPublish(boolean publish, String queryStr, IProgressMonitor monitor) {
636
        Set<T> result = new HashSet<>();
637
        Query query = getSession().createQuery(queryStr);
638
        query.setBoolean("publish", publish);
639
        @SuppressWarnings("unchecked")
640
        List<List<Integer>> partitionList = splitIdList(query.list(), DEFAULT_PARTITION_SIZE);
641
        for (List<Integer> taxonIdList : partitionList){
642
            List<TaxonBase> taxonList = taxonDao.loadList(taxonIdList, null);
643
            for (TaxonBase taxonBase : taxonList){
644
                if (taxonBase != null){
645
                    taxonBase.setPublish(publish);
646
                    result.add((T)CdmBase.deproxy(taxonBase));
647
                    monitor.worked(1);
648
                    if (monitor.isCanceled()){
649
                        return result;
650
                    }
651
                }
652
            }
653
        }
654
        return result;
655
    }
656

    
657

    
658
    /**
659
     * @param includeSharedTaxa
660
     * @param subTreeIndex
661
     * @return
662
     */
663
    private String synonymForSubtreeQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex, SelectMode mode) {
664
        String queryStr = "SELECT " + mode.hql("syn")
665
                + " FROM TaxonNode tn JOIN tn.taxon t JOIN t.synonyms syn"
666
                + " WHERE tn.treeIndex like '%s%%' ";
667
        if (!includeSharedTaxa){
668
            queryStr += " AND t.taxonNodes.size <= 1  ";
669
        }
670
        queryStr = String.format(queryStr, subTreeIndex.toString());
671

    
672
        return queryStr;
673
    }
674

    
675
    private enum SelectMode{
676
        COUNT(" count(*) "),
677
        ID ("id "),
678
        UUID("uuid "),
679
        FULL("");
680
        private String hql;
681
        SelectMode(String hql){
682
            this.hql = hql;
683
        }
684
        public String hql(String prefix){
685
            switch (this){
686
            case ID:
687
            case UUID:
688
                return CdmUtils.Nz(prefix)+"." + hql;
689
            case FULL:
690
                return CdmUtils.Nz(prefix) + hql;
691
            case COUNT:
692
            default: return hql;
693
            }
694

    
695
        }
696
    }
697

    
698
    private String acceptedForSubtreeQueryStr(boolean includeSharedTaxa, TreeIndex subTreeIndex, SelectMode mode) {
699
        String queryStr = "SELECT " + mode.hql("t")
700
                + " FROM TaxonNode tn JOIN tn.taxon t "
701
                + " WHERE tn.treeIndex like '%s%%' ";
702
        if (!includeSharedTaxa){
703
            queryStr += " AND t.taxonNodes.size <= 1  ";
704
        }
705
        queryStr = String.format(queryStr, subTreeIndex.toString());
706

    
707
        return queryStr;
708
    }
709

    
710
    @Override
711
    public List<UuidAndTitleCache<TaxonNode>> getTaxonNodeUuidAndTitleCacheOfAcceptedTaxaByClassification(Classification classification, Integer limit, String pattern, boolean searchForClassifications) {
712
        int classificationId = classification.getId();
713
        // StringBuffer excludeUuids = new StringBuffer();
714
   //, taxon.name.rank
715
         String queryString = "SELECT nodes.uuid, nodes.id,  taxon.titleCache, taxon.name.rank FROM TaxonNode AS nodes JOIN nodes.taxon as taxon WHERE nodes.classification.id = " + classificationId ;
716
         if (pattern != null){
717
             if (pattern.equals("?")){
718
                 limit = null;
719
             } else{
720
                 if (!pattern.endsWith("*")){
721
                     pattern += "%";
722
                 }
723
                 pattern = pattern.replace("*", "%");
724
                 pattern = pattern.replace("?", "%");
725
                 queryString = queryString + " AND taxon.titleCache like (:pattern) " ;
726
             }
727
         }
728

    
729

    
730

    
731
         Query query = getSession().createQuery(queryString);
732

    
733

    
734
         if (limit != null){
735
             query.setMaxResults(limit);
736
         }
737

    
738
         if (pattern != null && !pattern.equals("?")){
739
             query.setParameter("pattern", pattern);
740
         }
741
         @SuppressWarnings("unchecked")
742
         List<Object[]> result = query.list();
743

    
744
         if (searchForClassifications){
745
             queryString = "SELECT nodes.uuid, nodes.id,  nodes.classification.titleCache, NULLIF(1,1) FROM TaxonNode AS nodes WHERE nodes.classification.id = " + classificationId + " AND nodes.taxon IS NULL";
746
             if (pattern != null){
747
                 if (pattern.equals("?")){
748
                     limit = null;
749
                 } else{
750
                     if (!pattern.endsWith("*")){
751
                         pattern += "%";
752
                     }
753
                     pattern = pattern.replace("*", "%");
754
                     pattern = pattern.replace("?", "%");
755
                     queryString = queryString + " AND nodes.classification.titleCache like (:pattern) " ;
756
                 }
757
             }
758
              query = getSession().createQuery(queryString);
759

    
760

    
761
             if (limit != null){
762
                 query.setMaxResults(limit);
763
             }
764

    
765
             if (pattern != null && !pattern.equals("?")){
766
                 query.setParameter("pattern", pattern);
767
             }
768
             List<Object[]> resultClassifications = query.list();
769

    
770
             result.addAll(resultClassifications);
771
         }
772

    
773
         if(result.size() == 0){
774
             return null;
775
         }else{
776
             List<UuidAndTitleCache<TaxonNode>> list = new ArrayList<UuidAndTitleCache<TaxonNode>>(result.size());
777
             if (result != null && !result.isEmpty()){
778
                 if (result.iterator().next().length == 4){
779
                     Collections.sort(result, new UuidAndTitleCacheTaxonComparator());
780
                 }
781
             }
782
             for (Object object : result){
783

    
784
                 Object[] objectArray = (Object[]) object;
785

    
786
                 UUID uuid = (UUID)objectArray[0];
787
                 Integer id = (Integer) objectArray[1];
788
                 String titleCache = (String) objectArray[2];
789

    
790
                 list.add(new UuidAndTitleCache<TaxonNode>(TaxonNode.class, uuid, id, titleCache));
791
             }
792

    
793
             return list;
794
         }
795
    }
796

    
797

    
798

    
799

    
800
}
(4-4/5)