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
37
        extends CdmEntityDaoBase<TaxonNode>
38
        implements ITaxonNodeFilterDao {
39

    
40
    private static final String DESCRIPTION_ELEMENTS = "descriptionElements";
41

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

    
44
    private static final String HQL_TRUE = " 1 "; //maybe we can/should use 'true' instead, needs to be checked for all DB types
45
    private static final String HQL_FALSE = " 0 "; //maybe we can/should use 'false' instead, needs to be checked for all DB types
46

    
47
    @Autowired
48
    private ITaxonNodeDao taxonNodeDao;
49

    
50
    @Autowired
51
    private IDefinedTermDao termDao;
52

    
53
    public TaxonNodeFilterDaoHibernateImpl() {
54
        super(TaxonNode.class);
55
    }
56

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

    
63
        return result;
64
    }
65

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

    
72
        list = deduplicate(list);
73
        return list;
74
    }
75

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

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

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

    
108
        return fullQuery;
109
    }
110

    
111
    private String getOrderBy(TaxonNodeFilter filter, String selectPart) {
112
        String orderBy = "";
113
        if (filter.getOrderBy()!= null && !selectPart.contains("count")){
114
            orderBy = "ORDER BY " + filter.getOrderBy().getHql();
115
        }
116
        return orderBy;
117
    }
118

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

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

    
137
    private String getAreaFilter(TaxonNodeFilter filter) {
138
        String result = "";
139
        List<LogicFilter<NamedArea>> areaFilter = filter.getAreaFilter();
140
        boolean isFirst = true;
141
        List<Integer> areaIds = new ArrayList<>();
142
        for (LogicFilter<NamedArea> singleFilter : areaFilter){
143
            areaIds = getChildAreasRecursively(singleFilter.getUuid());
144
            String op = isFirst ? "" : op2Hql(singleFilter.getOperator());
145
            result = String.format("(%s%s(" + DESCRIPTION_ELEMENTS + ".feature.uuid='" + FEATURE_UUID + "' "
146
                    + " AND " + DESCRIPTION_ELEMENTS + ".area.id in (%s)))"
147
                    + " AND " + DESCRIPTION_ELEMENTS + ".status.absenceTerm = %s " ,
148
                    result, op, StringUtils.collectionToCommaDelimitedString(areaIds),
149
                    HQL_FALSE);
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<UUID> query = getSession().createQuery(queryStr, UUID.class);
162
        List<UUID> childAreas = 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
    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)