Project

General

Profile

Download (11.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 *
3
 */
4
package eu.etaxonomy.cdm.persistence.dao.hibernate.taxon;
5

    
6
import java.util.ArrayList;
7
import java.util.List;
8
import java.util.UUID;
9

    
10
import org.hibernate.Query;
11
import org.springframework.beans.factory.annotation.Autowired;
12
import org.springframework.stereotype.Repository;
13
import org.springframework.util.StringUtils;
14

    
15
import eu.etaxonomy.cdm.common.CdmUtils;
16
import eu.etaxonomy.cdm.filter.LogicFilter;
17
import eu.etaxonomy.cdm.filter.LogicFilter.Op;
18
import eu.etaxonomy.cdm.filter.TaxonNodeFilter;
19
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
20
import eu.etaxonomy.cdm.model.location.NamedArea;
21
import eu.etaxonomy.cdm.model.name.Rank;
22
import eu.etaxonomy.cdm.model.taxon.Classification;
23
import eu.etaxonomy.cdm.model.taxon.Taxon;
24
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
25
import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
26
import eu.etaxonomy.cdm.persistence.dao.hibernate.common.CdmEntityDaoBase;
27
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
28
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeFilterDao;
29

    
30
/**
31
 * DAO to retrieve taxon node uuids according to a {@link TaxonNodeFilter}.
32
 *
33
 * @author a.mueller
34
 */
35
@Repository
36
public class TaxonNodeFilterDaoHibernateImpl extends CdmEntityDaoBase<TaxonNode> implements ITaxonNodeFilterDao {
37

    
38
    private static final String DESCRIPTION_ELEMENTS = "descriptionElements";
39

    
40
    private static final String FEATURE_UUID = "9fc9d10c-ba50-49ee-b174-ce83fc3f80c6";
41

    
42
    private static final String HQL_TRUE = " 1 "; //maybe we can/should use 'true' instead, needs to be checked for all DB types
43

    
44
    @Autowired
45
    private ITaxonNodeDao taxonNodeDao;
46

    
47
    @Autowired
48
    private IDefinedTermDao termDao;
49

    
50
    public TaxonNodeFilterDaoHibernateImpl() {
51
        super(TaxonNode.class);
52
    }
53

    
54

    
55
    /**
56
     * {@inheritDoc}
57
     */
58
    @Override
59
    public long count(TaxonNodeFilter filter){
60
        String queryStr = query(filter, "count(*) as n ");
61
        Query query = getSession().createQuery(queryStr);
62
        long result = (Long)query.uniqueResult();
63

    
64
        return result;
65
    }
66

    
67
    /**
68
     * {@inheritDoc}
69
     */
70
    @Override
71
    public List<UUID> listUuids(TaxonNodeFilter filter){
72
        String queryStr = query(filter, "tn.uuid");
73
        Query query = getSession().createQuery(queryStr);
74
        List<UUID> list = castToUuidList(query.list());
75

    
76
        list = deduplicate(list);
77
        return list;
78
    }
79

    
80
    /**
81
     * {@inheritDoc}
82
     */
83
    @Override
84
    public List<Integer> idList(TaxonNodeFilter filter){
85
        String queryStr = query(filter, "tn.id");
86
        Query query = getSession().createQuery(queryStr);
87
        List<Integer> list = castToIntegerList(query.list());
88

    
89
        list = deduplicate(list);
90
        return list;
91
    }
92

    
93
    //maybe we will later want to have ordering included
94
    private String query(TaxonNodeFilter filter, String selectPart){
95
        String select = " SELECT " + selectPart;
96
        String from = getFrom(filter);
97
        String subtreeFilter = getSubtreeFilter(filter);
98
        String taxonNodeFilter = getTaxonNodeFilter(filter);
99
        String classificationFilter = getClassificationFilter(filter);
100
        String taxonFilter = getTaxonFilter(filter);
101
        String rootNodeFilter = getRootNodeFilter(filter);
102
        String rankMaxFilter = getRankMaxFilter(filter);
103
        String rankMinFilter = getRankMinFilter(filter);
104
        String areaFilter = getAreaFilter(filter);
105
        String unpublishFilter = getUnpublishFilter(filter);
106

    
107
        String fullFilter = getFullFilter(subtreeFilter, taxonNodeFilter,
108
                classificationFilter, taxonFilter,
109
                rankMaxFilter, rankMinFilter, areaFilter, rootNodeFilter,
110
                unpublishFilter);
111
//        String groupBy = " GROUP BY tn.uuid ";
112
        String groupBy = "";
113
        String fullQuery = select + from + " WHERE " + fullFilter + groupBy;
114
        return fullQuery;
115

    
116
    }
117

    
118
    private String getFrom(TaxonNodeFilter filter){
119
        String from = " FROM TaxonNode tn ";
120
        if (hasTaxonFilter(filter)){
121
            from += " LEFT JOIN tn.taxon taxon ";  //LEFT to allow includeRootNode
122
        }
123
        if(!filter.getAreaFilter().isEmpty()){
124
            from += " INNER JOIN taxon.descriptions descriptions "
125
                  + " INNER JOIN descriptions.descriptionElements " + DESCRIPTION_ELEMENTS + " ";
126
        }
127
        return from;
128
    }
129

    
130
    /**
131
     * @return
132
     */
133
    private boolean hasTaxonFilter(TaxonNodeFilter filter) {
134
        boolean result = !filter.getAreaFilter().isEmpty()
135
                || !filter.isIncludeUnpublished();
136
        return result;
137
    }
138

    
139

    
140
    private String getAreaFilter(TaxonNodeFilter filter) {
141
        String result = "";
142
        List<LogicFilter<NamedArea>> areaFilter = filter.getAreaFilter();
143
        boolean isFirst = true;
144
        List<Integer> areaIds = new ArrayList<>();
145
        for (LogicFilter<NamedArea> singleFilter : areaFilter){
146
            areaIds = getChildAreasRecursively(singleFilter.getUuid());
147
            String op = isFirst ? "" : op2Hql(singleFilter.getOperator());
148
            result = String.format("(%s%s("+DESCRIPTION_ELEMENTS+".feature.uuid='"+FEATURE_UUID+"' AND "+DESCRIPTION_ELEMENTS+".area.id in (%s)))",
149
                    result, op, StringUtils.collectionToCommaDelimitedString(areaIds));
150
            isFirst = false;
151
        }
152
        return result;
153
    }
154

    
155
    private List<Integer> getChildAreasRecursively(UUID uuid){
156
        List<Integer> areaIds = new ArrayList<>();
157
        NamedArea area = HibernateProxyHelper.deproxy(termDao.load(uuid), NamedArea.class);
158
        areaIds.add(area.getId());
159
        String queryStr = String.format("SELECT includes.uuid FROM DefinedTermBase t inner join t.includes includes WHERE t.uuid = '%s'",
160
                area.getUuid().toString());
161
        Query query = getSession().createQuery(queryStr);
162
        List<UUID> childAreas = castToUuidList(query.list());
163
        for (UUID childArea : childAreas) {
164
            areaIds.addAll(getChildAreasRecursively(childArea));
165
        }
166
        return areaIds;
167
    }
168

    
169

    
170

    
171

    
172
    /**
173
     * @param filter
174
     * @return
175
     */
176
    private String getRootNodeFilter(TaxonNodeFilter filter) {
177
        String result = "";
178
        if (!filter.isIncludeRootNodes()){
179
            result = " ( tn.parent IS NOT NULL ) ";
180
        }
181
        return result;
182
    }
183

    
184
    private String getUnpublishFilter(TaxonNodeFilter filter) {
185
        String result = "";
186
        if (!filter.isIncludeUnpublished()){
187
            result = " ( taxon.publish = "+HQL_TRUE+" OR tn.parent IS NULL ) ";
188
        }
189
        return result;
190
    }
191

    
192

    
193
    /**
194
     * @param subtreeFilter
195
     * @param taxonNodeFilter
196
     * @param classificationFilter
197
     * @param taxonFilter
198
     * @param rankMinFilter
199
     * @param rankMaxFilter
200
     * @param rootNodeFilter
201
     * @return
202
     */
203
    private String getFullFilter(String subtreeFilter, String taxonNodeFilter, String classificationFilter,
204
            String taxonFilter, String rankMaxFilter, String rankMinFilter, String areaFilter, String rootNodeFilter,
205
            String unpublishFilter) {
206
        String result = " (1=1 ";
207
        result = CdmUtils.concat(") AND (", result, subtreeFilter, taxonNodeFilter,
208
                classificationFilter, taxonFilter, rankMaxFilter, rankMinFilter, areaFilter, rootNodeFilter,
209
                unpublishFilter) + ") ";
210
        return result;
211
    }
212

    
213

    
214
    /**
215
     * @param list
216
     * @return
217
     */
218
    private <T> List<T> deduplicate(List<T> list) {
219
        List<T> result = new ArrayList<>();
220
        for (T uuid : list){
221
            if (!result.contains(uuid)){
222
                result.add(uuid);
223
            }
224
        }
225
        return result;
226
    }
227

    
228

    
229
    private String getSubtreeFilter(TaxonNodeFilter filter) {
230
        String result = "";
231
        List<LogicFilter<TaxonNode>> subtreeFilter = filter.getSubtreeFilter();
232
        initializeSubtreeIndex(subtreeFilter);
233
        boolean isFirst = true;
234
        for (LogicFilter<TaxonNode> singleFilter : subtreeFilter){
235
            String treeIndex = singleFilter.getTreeIndex();
236
            String op = isFirst ? "" : op2Hql(singleFilter.getOperator());
237
            if (treeIndex != null){
238
                result = String.format("(%s%s(tn.treeIndex like '%s%%'))", result, op, treeIndex);
239
            }else{
240
                result = String.format("(%s%s(%s))", result, op, "(1=0)");
241
            }
242
            isFirst = false;
243
        }
244
        return result;
245
    }
246

    
247

    
248
    private String getTaxonNodeFilter(TaxonNodeFilter filter) {
249
        String result = "";
250
        List<LogicFilter<TaxonNode>> taxonNodeFilter = filter.getTaxonNodesFilter();
251
        boolean isFirst = true;
252
        for (LogicFilter<TaxonNode> singleFilter : taxonNodeFilter){
253
            String uuid = singleFilter.getUuid().toString();
254
            String op = isFirst ? "" : op2Hql(singleFilter.getOperator());
255
            result = String.format("(%s%s(tn.uuid = '%s'))", result, op, uuid);
256
            isFirst = false;
257
        }
258
        return result;
259
    }
260

    
261
    private String getRankMaxFilter(TaxonNodeFilter filter) {
262
        String result = "";
263
        LogicFilter<Rank> rankFilter = filter.getRankMax();
264
        if(rankFilter!=null){
265
            UUID rankUuid = rankFilter.getUuid();
266
            Rank rank = (Rank) termDao.load(rankUuid);
267
            result = String.format("(tn.taxon.name.rank.orderIndex >= %s)", rank.getOrderIndex());
268
        }
269
        return result;
270
    }
271

    
272
    private String getRankMinFilter(TaxonNodeFilter filter) {
273
        String result = "";
274
        LogicFilter<Rank> rankFilter = filter.getRankMin();
275
        if(rankFilter!=null){
276
            UUID rankUuid = rankFilter.getUuid();
277
            Rank rank = (Rank) termDao.load(rankUuid);
278
            result = String.format("(tn.taxon.name.rank.orderIndex <= %s)", rank.getOrderIndex());
279
        }
280
        return result;
281
    }
282

    
283
    private String getClassificationFilter(TaxonNodeFilter filter) {
284
        String result = "";
285
        List<LogicFilter<Classification>> classificationFilter = filter.getClassificationFilter();
286
        boolean isFirst = true;
287
        for (LogicFilter<Classification> singleFilter : classificationFilter){
288
            String uuid = singleFilter.getUuid().toString();
289
            String op = isFirst ? "" : op2Hql(singleFilter.getOperator());
290
            result = String.format("(%s%s(tn.classification.uuid = '%s'))", result, op, uuid);
291
//            System.out.println(result);
292
            isFirst = false;
293
        }
294
        return result;
295
    }
296

    
297
    private String getTaxonFilter(TaxonNodeFilter filter) {
298
        String result = "";
299
        List<LogicFilter<Taxon>> taxonFilter = filter.getTaxonFilter();
300
        boolean isFirst = true;
301
        for (LogicFilter<Taxon> singleFilter : taxonFilter){
302
            String uuid = singleFilter.getUuid().toString();
303
            String op = isFirst ? "" : op2Hql(singleFilter.getOperator());
304
            result = String.format("(%s%s(tn.taxon.uuid = '%s'))", result, op, uuid);
305
//            System.out.println(result);
306
            isFirst = false;
307
        }
308
        return result;
309
    }
310

    
311

    
312
    /**
313
     * @param subtreeFilter
314
     */
315
    private void initializeSubtreeIndex(List<LogicFilter<TaxonNode>> subtreeFilter) {
316
        for (LogicFilter<TaxonNode> filter : subtreeFilter){
317
            if (filter.getTreeIndex() == null){
318
                //TODO finde without loading, best be sending full list and returning tree indexes
319
                TaxonNode node = taxonNodeDao.findByUuid(filter.getUuid());
320
                if (node != null){
321
                    filter.setTreeIndex(node.treeIndex());
322
                }
323
            }
324
        }
325

    
326
    }
327

    
328

    
329
    /**
330
     * Returns the HQL string for this operation
331
     *
332
     */
333
    private String op2Hql(Op op){
334
        return op == Op.NOT ? " AND NOT " : op.toString();
335
    }
336

    
337
    @SuppressWarnings("unchecked")
338
    private List<UUID> castToUuidList(List<?> queryList){
339
        return (List<UUID>) queryList;
340
    }
341
    @SuppressWarnings("unchecked")
342
    private List<Integer> castToIntegerList(List<?> queryList){
343
        return (List<Integer>) queryList;
344
    }
345
}
(5-5/5)