Project

General

Profile

Download (12 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.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.hibernate.common.CdmEntityDaoBase;
26
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeDao;
27
import eu.etaxonomy.cdm.persistence.dao.taxon.ITaxonNodeFilterDao;
28
import eu.etaxonomy.cdm.persistence.dao.term.IDefinedTermDao;
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
    private static final String HQL_FALSE = " 0 "; //maybe we can/should use 'false' instead, needs to be checked for all DB types
44

    
45
    @Autowired
46
    private ITaxonNodeDao taxonNodeDao;
47

    
48
    @Autowired
49
    private IDefinedTermDao termDao;
50

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

    
55
    @Override
56
    public long count(TaxonNodeFilter filter){
57
        String queryStr = query(filter, "count(*) as n ");
58
        Query<Long> query = getSession().createQuery(queryStr, Long.class);
59
        long result = query.uniqueResult();
60

    
61
        return result;
62
    }
63

    
64
    @Override
65
    public List<UUID> listUuids(TaxonNodeFilter filter){
66
        String queryStr = query(filter, "tn.uuid");
67
        Query<UUID> query = getSession().createQuery(queryStr, UUID.class);
68
        List<UUID> list = query.list();
69

    
70
        list = deduplicate(list);
71
        return list;
72
    }
73

    
74
    @Override
75
    public List<Integer> idList(TaxonNodeFilter filter){
76
        String queryStr = query(filter, "tn.id");
77
        Query<Integer> query = getSession().createQuery(queryStr, Integer.class);
78
        List<Integer> list = query.list();
79
        list = deduplicate(list);
80
        return list;
81
    }
82

    
83
    //maybe we will later want to have ordering included
84
    private String query(TaxonNodeFilter filter, String selectPart){
85
        String select = " SELECT " + selectPart;
86
        String from = getFrom(filter);
87
        String subtreeFilter = getSubtreeFilter(filter);
88
        String taxonNodeFilter = getTaxonNodeFilter(filter);
89
        String classificationFilter = getClassificationFilter(filter);
90
        String taxonFilter = getTaxonFilter(filter);
91
        String rootNodeFilter = getRootNodeFilter(filter);
92
        String rankMaxFilter = getRankMaxFilter(filter);
93
        String rankMinFilter = getRankMinFilter(filter);
94
        String areaFilter = getAreaFilter(filter);
95
        String unpublishFilter = getUnpublishFilter(filter);
96

    
97
        String fullFilter = getFullFilter(subtreeFilter, taxonNodeFilter,
98
                classificationFilter, taxonFilter,
99
                rankMaxFilter, rankMinFilter, areaFilter, rootNodeFilter,
100
                unpublishFilter);
101
//        String groupBy = " GROUP BY tn.uuid ";
102
        String groupBy = "";
103
        String orderBy = getOrderBy(filter, selectPart);
104
        String fullQuery = select + from + " WHERE " + fullFilter + groupBy + orderBy;
105

    
106
        return fullQuery;
107

    
108
    }
109

    
110
    private String getOrderBy(TaxonNodeFilter filter, String selectPart) {
111
        String orderBy = "";
112
        if (filter.getOrderBy()!= null && !selectPart.contains("count")){
113
            orderBy = "ORDER BY " + filter.getOrderBy().getHql();
114
        }
115
        return orderBy;
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
    private boolean hasTaxonFilter(TaxonNodeFilter filter) {
131
        boolean result = !filter.getAreaFilter().isEmpty()
132
                || !filter.isIncludeUnpublished();
133
        return result;
134
    }
135

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

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

    
168

    
169

    
170

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

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

    
191

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

    
212

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

    
227

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

    
246

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

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

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

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

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

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

    
321
    /**
322
     * Returns the HQL string for this operation
323
     */
324
    private String op2Hql(Op op){
325
        return op == Op.NOT ? " AND NOT " : op.toString();
326
    }
327
}
(5-5/6)