Project

General

Profile

Download (17.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
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.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
21
import org.hibernate.query.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 = LogManager.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
    public List<TaxonNode> listRankSpecificRootNodes(Classification classification, TaxonNode taxonNode, Rank rank,
60
            boolean includeUnpublished, Integer limit, Integer start, List<String> propertyPaths, int queryIndex){
61

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

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

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

    
83
        return results;
84

    
85
    }
86

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

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

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

    
113
        Query<R> query1;
114
        Query<R> 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, resultClass);
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, resultClass);
162
            query2 = getSession().createQuery(hql2, resultClass);
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.setParameter("publish", true);
186
            if(query2 != null) {
187
                query2.setParameter("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<TaxonNode> query = prepareListChildrenOf(taxon, classification, subtree, false, includeUnpublished, TaxonNode.class);
203

    
204
         addPageSizeAndNumber(query, pageSize, pageIndex);
205

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

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

    
222
        Query<TaxonNode> query = getSession().createQuery(queryString, TaxonNode.class);
223
        query.setParameter("classificationUuid", classificationUuid);
224

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

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

    
237
         addPageSizeAndNumber(query, pageSize, pageIndex);
238

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

    
248
    @Override
249
    public Long countChildrenOf(Taxon taxon, Classification classification, TaxonNode subtree,
250
            boolean includeUnpublished){
251
        Query<Long> query = prepareListChildrenOf(taxon, classification, subtree, true, includeUnpublished, Long.class);
252
        Long count = query.uniqueResult();
253
        return count;
254
    }
255

    
256
    @Override
257
    public Long countSiblingsOf(Taxon taxon, Classification classification, boolean includeUnpublished){
258
        Query<Long> query = prepareListSiblingsOf(taxon, classification, includeUnpublished, true, Long.class);
259
        Long count = query.uniqueResult();
260
        return count;
261
    }
262

    
263
    private <R extends Object> Query<R> prepareListChildrenOf(Taxon taxon, Classification classification, TaxonNode subtree,
264
            boolean doCount, boolean includeUnpublished, Class<R> resultClass){
265

    
266
    	 String selectWhat = doCount ? "COUNT(cn)" : "cn";
267

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

    
293
    private <R extends Object> Query<R> prepareListSiblingsOf(Taxon taxon, Classification classification,
294
            boolean includeUnpublished, boolean doCount, Class<R> resultClass){
295

    
296
         String selectWhat = doCount ? "COUNT(tn)" : "tn";
297
         String whereUnpublished = includeUnpublished? "" : " AND t.publish = :publish ";
298

    
299
         String subSelect =
300
                   " SELECT tn.parent "
301
                 + " FROM TaxonNode AS tn "
302
                 + "     JOIN tn.classification AS c "
303
                 + "     JOIN tn.taxon AS t "
304
                 + " WHERE t = :taxon "
305
                 + "   AND c = :classification "
306
                 + whereUnpublished;
307
         String hql = " SELECT " + selectWhat
308
                 + " FROM TaxonNode as tn "
309
                 + " WHERE tn.parent IN ( " + subSelect + ")";
310
         Query<R> query = getSession().createQuery(hql, resultClass);
311
         query.setParameter("taxon", taxon);
312
         query.setParameter("classification", classification);
313
         if (!includeUnpublished){
314
             query.setParameter("publish", true);
315
         }
316
         return query;
317
    }
318

    
319

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

    
332
        TaxonNode rootNode = persistentObject.getRootNode();
333
        persistentObject.removeRootNode();
334
        taxonNodeDao.delete(rootNode);
335
        super.delete(persistentObject);
336

    
337
        return persistentObject.getUuid();
338
    }
339

    
340
    @Override
341
    public ClassificationLookupDTO classificationLookup(Classification classification) {
342

    
343
        ClassificationLookupDTO classificationLookupDTO = new ClassificationLookupDTO(classification);
344

    
345
        String hql =
346
                " SELECT t.id, n.rank, tp.id "
347
              + " FROM TaxonNode AS tn "
348
              +   " JOIN tn.classification AS c "
349
              +   " JOIN tn.taxon AS t "
350
              +   " JOIN t.name AS n "
351
              +   " LEFT JOIN tn.parent AS tnp "
352
              +   " LEFT JOIN tnp.taxon as tp "
353
              + " WHERE c = :classification";
354

    
355
        Query<Object[]> query = getSession().createQuery(hql, Object[].class);
356
        query.setParameter("classification", classification);
357

    
358
        List<Object[]> result = query.list();
359
        for(Object[] row : result) {
360
            Integer parentId = null;
361
            parentId = (Integer) row[2];
362
            classificationLookupDTO.add((Integer)row[0], (Rank)row[1], parentId);
363
        }
364

    
365
        return classificationLookupDTO ;
366
    }
367

    
368
    @Override
369
    public Map<UUID, TreeIndex> treeIndexForTaxonUuids(UUID classificationUuid,
370
            List<UUID> taxonUuids) {
371
        String hql = " SELECT t.uuid, tn.treeIndex "
372
                + " FROM Taxon t JOIN t.taxonNodes tn "
373
                + " WHERE (1=1)"
374
                + "     AND tn.classification.uuid = :classificationUuid "
375
                + "     AND t.uuid IN (:taxonUuids) "
376
                ;
377
        Query<Object[]> query =  getSession().createQuery(hql, Object[].class);
378
        query.setParameter("classificationUuid", classificationUuid);
379
        query.setParameterList("taxonUuids", taxonUuids);
380

    
381
        Map<UUID, TreeIndex> result = new HashMap<>();
382
        List<Object[]> list = query.list();
383
        for (Object[] o : list){
384
            result.put((UUID)o[0], TreeIndex.NewInstance((String)o[1]));
385
        }
386
        return result;
387
    }
388

    
389
    @Override
390
    public Set<TreeIndex> getMarkedTreeIndexes(MarkerType markerType, Boolean flag){
391
        String hql = " SELECT tn.treeIndex "
392
                + " FROM Taxon t "
393
                + "    JOIN t.taxonNodes tn "
394
                + "    JOIN t.markers m "
395
                + " WHERE (1=1)"
396
                + "    AND m.markerType = :markerType "
397
                ;
398
        if (flag != null){
399
            hql += "  AND m.flag = :flag ";
400

    
401
        }
402

    
403
        Query<String> query =  getSession().createQuery(hql, String.class);
404
        if (flag != null){
405
            query.setParameter("flag", flag);
406
        }
407
        query.setParameter("markerType", markerType);
408

    
409
        Set<TreeIndex> result = new HashSet<>();
410

    
411
        List<String> list = query.list();
412
        for (String o : list){
413
            result.add(TreeIndex.NewInstance(o));
414
        }
415
        return result;
416
    }
417

    
418
    @Override
419
    public Map<UUID, UUID> getTaxonNodeUuidByTaxonUuid(UUID classificationUuid, List<UUID> taxonUuids) {
420
        String hql = " SELECT t.uuid, tn.uuid "
421
                + " FROM Taxon t JOIN t.taxonNodes tn "
422
                + " WHERE (1=1)"
423
                + "     AND tn.classification.uuid = :classificationUuid "
424
                + "     AND t.uuid IN (:taxonUuids) "
425
                ;
426
        Query<Object[]> query =  getSession().createQuery(hql, Object[].class);
427
        query.setParameter("classificationUuid", classificationUuid);
428
        query.setParameterList("taxonUuids", taxonUuids);
429

    
430
        Map<UUID, UUID> result = new HashMap<>();
431
        List<Object[]> list = query.list();
432
        for (Object[] o : list){
433
            result.put((UUID)o[0], (UUID)o[1]);
434
        }
435
        return result;
436
    }
437
}
(1-1/6)