Project

General

Profile

Download (17.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.util.ArrayList;
13
import java.util.HashMap;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Set;
18
import java.util.UUID;
19

    
20
import org.apache.log4j.Logger;
21
import org.hibernate.Query;
22
import org.springframework.beans.factory.annotation.Autowired;
23
import org.springframework.beans.factory.annotation.Qualifier;
24
import org.springframework.stereotype.Repository;
25

    
26
import eu.etaxonomy.cdm.model.common.MarkerType;
27
import eu.etaxonomy.cdm.model.common.TreeIndex;
28
import eu.etaxonomy.cdm.model.name.Rank;
29
import eu.etaxonomy.cdm.model.taxon.Classification;
30
import eu.etaxonomy.cdm.model.taxon.Taxon;
31
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
32
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.IdentifiableDaoBase;
33
import eu.etaxonomy.cdm.persistence.dao.taxon.IClassificationDao;
34
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
35
import eu.etaxonomy.cdm.persistence.dto.ClassificationLookupDTO;
36

    
37
/**
38
 * @author a.mueller
39
 * @since 16.06.2009
40
 */
41
@Repository
42
@Qualifier("classificationDaoHibernateImpl")
43
public class ClassificationDaoHibernateImpl
44
        extends IdentifiableDaoBase<Classification>
45
        implements IClassificationDao {
46
    @SuppressWarnings("unused")
47
    private static final Logger logger = Logger.getLogger(ClassificationDaoHibernateImpl.class);
48

    
49
    @Autowired
50
    private ITaxonNodeDao taxonNodeDao;
51

    
52
    public ClassificationDaoHibernateImpl() {
53
        super(Classification.class);
54
        indexedClasses = new Class[1];
55
        indexedClasses[0] = Classification.class;
56
    }
57

    
58
    @Override
59
    @SuppressWarnings("unchecked")
60
    public List<TaxonNode> listRankSpecificRootNodes(Classification classification, TaxonNode taxonNode, Rank rank,
61
            boolean includeUnpublished, Integer limit, Integer start, List<String> propertyPaths, int queryIndex){
62

    
63
        List<TaxonNode> results = new ArrayList<>();
64
        Query[] queries = prepareRankSpecificRootNodes(classification, taxonNode, rank, includeUnpublished, false);
65

    
66
        // since this method is using two queries sequentially the handling of limit and start
67
        // is a bit more complex
68
        // the prepareRankSpecificRootNodes returns 1 or 2 queries
69

    
70
        Query q = queries[queryIndex];
71
        if(limit != null) {
72
            q.setMaxResults(limit);
73
            if(start != null) {
74
                q.setFirstResult(start);
75
            }
76
        }
77
//        long start_t = System.currentTimeMillis();
78
        results = q.list();
79
//        System.err.println("dao.listRankSpecificRootNodes() - query[" + queryIndex + "].list() " + (System.currentTimeMillis() - start_t));
80
//        start_t = System.currentTimeMillis();
81
        defaultBeanInitializer.initializeAll(results, propertyPaths);
82
//        System.err.println("dao.listRankSpecificRootNodes() - defaultBeanInitializer.initializeAll() " + (System.currentTimeMillis() - start_t));
83

    
84
        return results;
85

    
86
    }
87

    
88
    @Override
89
    public long[] countRankSpecificRootNodes(Classification classification, TaxonNode subtree, boolean includeUnpublished, Rank rank) {
90

    
91
        long[] result = new long[(rank == null ? 1 : 2)];
92
        Query[] queries = prepareRankSpecificRootNodes(classification, subtree, rank, includeUnpublished, true);
93
        int i = 0;
94
        for(Query q : queries) {
95
            result[i++] = (Long)q.uniqueResult();
96
        }
97
        return result;
98
    }
99

    
100
    /**
101
     * See <a href="https://dev.e-taxonomy.eu/redmine/projects/edit/wiki/CdmClassificationRankSpecificRootnodes">
102
     * https://dev.e-taxonomy.eu/redmine/projects/edit/wiki/CdmClassificationRankSpecificRootnodes</a>
103
     *
104
     * @param classification
105
     * @param rank
106
     * @return
107
     *      one or two Queries as array, depending on the <code>rank</code> parameter:
108
     *      <code>rank == null</code>: array with one item, <code>rank != null</code>: array with two items.
109
     */
110
    private Query[] prepareRankSpecificRootNodes(Classification classification,
111
            TaxonNode subtree, Rank rank,
112
            boolean includeUnpublished, boolean doCount) {
113
        Query query1;
114
        Query query2 = null;
115

    
116
        String whereClassification = classification != null? " AND tn.classification = :classification " : "";
117
        String whereUnpublished = includeUnpublished? "" : " AND tn.taxon.publish = :publish ";
118
        String whereSubtree = subtree != null ? " AND tn.treeIndex like :treeIndexLike " : "";
119
        TreeIndex treeIndex = TreeIndex.NewInstance(subtree);
120
        String whereHighest =
121
                treeIndex == null ? " tn.parent.parent = null ":
122
                treeIndex.isTreeRoot() ? " tn.parent.treeIndex = :treeIndex ":
123
                            " tn.treeIndex = :treeIndex "   ;
124

    
125
        String selectWhat = doCount ? "COUNT(distinct tn)" : "DISTINCT tn";
126

    
127
        String joinFetch = doCount ? "" : " JOIN FETCH tn.taxon t JOIN FETCH t.name n LEFT JOIN FETCH n.rank LEFT JOIN FETCH t.secSource ss LEFT JOIN FETCH ss.citation ";
128

    
129
        if(rank == null){
130
            String hql = "SELECT " + selectWhat +
131
                    " FROM TaxonNode tn" +
132
                        joinFetch +
133
                    " WHERE " + whereHighest +
134
                    whereClassification + whereUnpublished;
135
            query1 = getSession().createQuery(hql);
136
        } else {
137
            // this is for the cases
138
            //   - exact match of the ranks
139
            //   - rank of root node is lower but it has no parents
140
            String hql1 = "SELECT " + selectWhat +
141
                    " FROM TaxonNode tn " +
142
                       joinFetch +
143
                    " WHERE " +
144
                    " (tn.taxon.name.rank = :rank" +
145
                    "   OR ((tn.taxon.name.rank.orderIndex > :rankOrderIndex) AND (" + whereHighest + "))" +
146
                    " )"
147
                    + whereClassification + whereSubtree + whereUnpublished ;
148

    
149
            // this is for the case
150
            //   - rank of root node is lower and it has a parent with higher rank
151
            String whereParentSubtree = subtree != null ? " AND parent.treeIndex like :treeIndexLike " : "";
152
            String hql2 = "SELECT " + selectWhat +
153
                    " FROM TaxonNode tn JOIN tn.parent as parent" +
154
                       joinFetch +
155
                    " WHERE " +
156
                    " (tn.taxon.name.rank.orderIndex > :rankOrderIndex "
157
                    + "     AND parent.taxon.name.rank.orderIndex < :rankOrderIndex )"
158
                    + whereClassification + whereSubtree
159
                    + whereParentSubtree + whereUnpublished;
160

    
161
            query1 = getSession().createQuery(hql1);
162
            query2 = getSession().createQuery(hql2);
163
            query1.setParameter("rank", rank);
164
            query1.setParameter("rankOrderIndex", rank.getOrderIndex());
165
            query2.setParameter("rankOrderIndex", rank.getOrderIndex());
166
        }
167

    
168
        //parameters
169
        if (classification != null){
170
            query1.setParameter("classification", classification);
171
            if(query2 != null) {
172
                query2.setParameter("classification", classification);
173
            }
174
        }
175
        if (subtree != null){
176
            query1.setParameter("treeIndex", subtree.treeIndex());
177
            if (rank != null){
178
                query1.setParameter("treeIndexLike", subtree.treeIndex()+"%");
179
            }
180
            if(query2 != null) {
181
                query2.setParameter("treeIndexLike", subtree.treeIndex()+"%");
182
            }
183
        }
184
        if (!includeUnpublished){
185
            query1.setBoolean("publish", true);
186
            if(query2 != null) {
187
                query2.setBoolean("publish", true);
188
            }
189
        }
190

    
191
        if(query2 != null) {
192
            return new Query[]{query1, query2};
193
        } else {
194
            return new Query[]{query1};
195
        }
196
    }
197

    
198
    @Override
199
    public List<TaxonNode> listChildrenOf(Taxon taxon, Classification classification, TaxonNode subtree, boolean includeUnpublished,
200
            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
201

    
202
         Query query = prepareListChildrenOf(taxon, classification, subtree, false, includeUnpublished);
203

    
204
         setPagingParameter(query, pageSize, pageIndex);
205

    
206
         @SuppressWarnings("unchecked")
207
         List<TaxonNode> result = query.list();
208
         //check if array is "empty" (not containing null objects)
209
         if(!result.isEmpty() && result.iterator().next()==null){
210
         	return java.util.Collections.emptyList();
211
         }
212
         defaultBeanInitializer.initializeAll(result, propertyPaths);
213
         return result;
214
    }
215

    
216
    @Override
217
    public TaxonNode getRootNode(UUID classificationUuid){
218
        String queryString =
219
                  " SELECT tn "
220
                + " FROM TaxonNode tn, Classification c "
221
                + " WHERE tn = c.rootNode AND c.uuid = :classificationUuid";
222

    
223
        Query query = getSession().createQuery(queryString);
224
        query.setParameter("classificationUuid", classificationUuid);
225

    
226
        @SuppressWarnings("unchecked")
227
        List<TaxonNode> results = query.list();
228
        if(results.size()!=1){
229
            return null;
230
        }
231
        return taxonNodeDao.load((results.iterator().next()).getUuid());
232
    }
233

    
234
    @Override
235
    public List<TaxonNode> listSiblingsOf(Taxon taxon, Classification classification, boolean includeUnpublished,
236
            Integer pageSize, Integer pageIndex, List<String> propertyPaths){
237
         Query query = prepareListSiblingsOf(taxon, classification, includeUnpublished, false);
238

    
239
         setPagingParameter(query, pageSize, pageIndex);
240

    
241
         @SuppressWarnings("unchecked")
242
         List<TaxonNode> result = query.list();
243
         //check if array is "empty" (not containing null objects)
244
         if(!result.isEmpty() && result.iterator().next()==null){
245
            return java.util.Collections.emptyList();
246
         }
247
         defaultBeanInitializer.initializeAll(result, propertyPaths);
248
         return result;
249
    }
250

    
251

    
252

    
253
    @Override
254
    public Long countChildrenOf(Taxon taxon, Classification classification, TaxonNode subtree,
255
            boolean includeUnpublished){
256
        Query query = prepareListChildrenOf(taxon, classification, subtree, true, includeUnpublished);
257
        Long count = (Long) query.uniqueResult();
258
        return count;
259
    }
260

    
261
    @Override
262
    public Long countSiblingsOf(Taxon taxon, Classification classification, boolean includeUnpublished){
263
        Query query = prepareListSiblingsOf(taxon, classification, includeUnpublished, true);
264
        Long count = (Long) query.uniqueResult();
265
        return count;
266
    }
267

    
268
    private Query prepareListChildrenOf(Taxon taxon, Classification classification, TaxonNode subtree,
269
            boolean doCount, boolean includeUnpublished){
270

    
271
    	 String selectWhat = doCount ? "COUNT(cn)" : "cn";
272

    
273
         String hql = "SELECT " + selectWhat
274
                 + " FROM TaxonNode AS tn "
275
                 + "   JOIN tn.classification AS c "
276
                 + "   JOIN tn.taxon AS t "
277
                 + "   JOIN tn.childNodes AS cn "
278
                 + " WHERE t = :taxon "
279
                 + "   AND c = :classification";
280
         if (!includeUnpublished){
281
             hql += "  AND cn.taxon.publish = :publish ";
282
         }
283
         if (subtree != null){
284
             hql += "  AND tn.treeIndex like :treeIndexLike ";
285
         }
286
         Query query = getSession().createQuery(hql);
287
         query.setParameter("taxon", taxon);
288
         query.setParameter("classification", classification);
289
         if (!includeUnpublished){
290
             query.setBoolean("publish", Boolean.TRUE);
291
         }
292
         if (subtree != null){
293
             query.setParameter("treeIndexLike", subtree.treeIndexLike());
294
         }
295
         return query;
296
    }
297

    
298
    private Query prepareListSiblingsOf(Taxon taxon, Classification classification,
299
            boolean includeUnpublished, boolean doCount){
300

    
301
         String selectWhat = doCount ? "COUNT(tn)" : "tn";
302
         String whereUnpublished = includeUnpublished? "" : " AND t.publish = :publish ";
303

    
304
         String subSelect =
305
                   " SELECT tn.parent "
306
                 + " FROM TaxonNode AS tn "
307
                 + "     JOIN tn.classification AS c "
308
                 + "     JOIN tn.taxon AS t "
309
                 + " WHERE t = :taxon "
310
                 + "   AND c = :classification "
311
                 + whereUnpublished;
312
         String hql = " SELECT " + selectWhat
313
                 + " FROM TaxonNode as tn "
314
                 + " WHERE tn.parent IN ( " + subSelect + ")";
315
         Query query = getSession().createQuery(hql);
316
         query.setParameter("taxon", taxon);
317
         query.setParameter("classification", classification);
318
         if (!includeUnpublished){
319
             query.setBoolean("publish", true);
320
         }
321
         return query;
322
    }
323

    
324

    
325
    @Override
326
    public UUID delete(Classification persistentObject){
327
        //delete all child nodes, then delete the tree
328
        if (persistentObject.getRootNode() != null){
329
            List<TaxonNode> nodes = persistentObject.getChildNodes();
330
            List<TaxonNode> nodesTmp = new ArrayList<>(nodes);
331
            for(TaxonNode node : nodesTmp){
332
                persistentObject.deleteChildNode(node, true);
333
                taxonNodeDao.delete(node, true);
334
            }
335
        }
336

    
337
        TaxonNode rootNode = persistentObject.getRootNode();
338
        persistentObject.removeRootNode();
339
        taxonNodeDao.delete(rootNode);
340
        super.delete(persistentObject);
341

    
342
        return persistentObject.getUuid();
343
    }
344

    
345
    @Override
346
    public ClassificationLookupDTO classificationLookup(Classification classification) {
347

    
348
        ClassificationLookupDTO classificationLookupDTO = new ClassificationLookupDTO(classification);
349

    
350
        String hql =
351
                " SELECT t.id, n.rank, tp.id "
352
              + " FROM TaxonNode AS tn "
353
              +   " JOIN tn.classification AS c "
354
              +   " JOIN tn.taxon AS t "
355
              +   " JOIN t.name AS n "
356
              +   " LEFT JOIN tn.parent AS tnp "
357
              +   " LEFT JOIN tnp.taxon as tp "
358
              + " WHERE c = :classification";
359

    
360
        Query query = getSession().createQuery(hql);
361
        query.setParameter("classification", classification);
362
        @SuppressWarnings("unchecked")
363
        List<Object[]> result = query.list();
364
        for(Object[] row : result) {
365
            Integer parentId = null;
366
            parentId = (Integer) row[2];
367
            classificationLookupDTO.add((Integer)row[0], (Rank)row[1], parentId);
368
        }
369

    
370
        return classificationLookupDTO ;
371
    }
372

    
373
    @Override
374
    public Map<UUID, TreeIndex> treeIndexForTaxonUuids(UUID classificationUuid,
375
            List<UUID> taxonUuids) {
376
        String hql = " SELECT t.uuid, tn.treeIndex "
377
                + " FROM Taxon t JOIN t.taxonNodes tn "
378
                + " WHERE (1=1)"
379
                + "     AND tn.classification.uuid = :classificationUuid "
380
                + "     AND t.uuid IN (:taxonUuids) "
381
                ;
382
        Query query =  getSession().createQuery(hql);
383
        query.setParameter("classificationUuid", classificationUuid);
384
        query.setParameterList("taxonUuids", taxonUuids);
385

    
386
        Map<UUID, TreeIndex> result = new HashMap<>();
387
        @SuppressWarnings("unchecked")
388
        List<Object[]> list = query.list();
389
        for (Object[] o : list){
390
            result.put((UUID)o[0], TreeIndex.NewInstance((String)o[1]));
391
        }
392
        return result;
393
    }
394

    
395
    @Override
396
    public Set<TreeIndex> getMarkedTreeIndexes(MarkerType markerType, Boolean flag){
397
        String hql = " SELECT tn.treeIndex "
398
                + " FROM Taxon t "
399
                + "    JOIN t.taxonNodes tn "
400
                + "    JOIN t.markers m "
401
                + " WHERE (1=1)"
402
                + "    AND m.markerType = :markerType "
403
                ;
404
        if (flag != null){
405
            hql += "  AND m.flag = :flag ";
406

    
407
        }
408

    
409
        Query query =  getSession().createQuery(hql);
410
        if (flag != null){
411
            query.setParameter("flag", flag);
412
        }
413
        query.setParameter("markerType", markerType);
414

    
415
        Set<TreeIndex> result = new HashSet<>();
416
        @SuppressWarnings("unchecked")
417
        List<String> list = query.list();
418
        for (String o : list){
419
            result.add(TreeIndex.NewInstance(o));
420
        }
421
        return result;
422
    }
423

    
424
    @Override
425
    public Map<UUID, UUID> getTaxonNodeUuidByTaxonUuid(UUID classificationUuid, List<UUID> taxonUuids) {
426
        String hql = " SELECT t.uuid, tn.uuid "
427
                + " FROM Taxon t JOIN t.taxonNodes tn "
428
                + " WHERE (1=1)"
429
                + "     AND tn.classification.uuid = :classificationUuid "
430
                + "     AND t.uuid IN (:taxonUuids) "
431
                ;
432
        Query query =  getSession().createQuery(hql);
433
        query.setParameter("classificationUuid", classificationUuid);
434
        query.setParameterList("taxonUuids", taxonUuids);
435

    
436
        Map<UUID, UUID> result = new HashMap<>();
437
        @SuppressWarnings("unchecked")
438
        List<Object[]> list = query.list();
439
        for (Object[] o : list){
440
            result.put((UUID)o[0], (UUID)o[1]);
441
        }
442
        return result;
443
    }
444

    
445
}
(1-1/6)