ff0a0ad4db8f627183d7d4d68f55df475af1dbc4
[ccsdk/features.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP : ccsdk features
4  * ================================================================================
5  * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
6  * All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  *
21  */
22 package org.onap.ccsdk.features.sdnr.wt.dataprovider.database.elasticsearch.data.rpctypehelper;
23
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Calendar;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.TimeZone;
30 import org.eclipse.jdt.annotation.Nullable;
31 import org.onap.ccsdk.features.sdnr.wt.common.YangHelper;
32 import org.onap.ccsdk.features.sdnr.wt.common.database.data.DbFilter;
33 import org.onap.ccsdk.features.sdnr.wt.common.database.queries.BoolQueryBuilder;
34 import org.onap.ccsdk.features.sdnr.wt.common.database.queries.QueryBuilder;
35 import org.onap.ccsdk.features.sdnr.wt.common.database.queries.QueryBuilders;
36 import org.onap.ccsdk.features.sdnr.wt.common.database.requests.SearchRequest;
37 import org.onap.ccsdk.features.sdnr.wt.dataprovider.database.elasticsearch.data.acessor.DataObjectAcessorPm;
38 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp;
39 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl;
40 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.YangHelper2;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.EntityInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.SortOrder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Filter;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Pagination;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Sortorder;
46 import org.opendaylight.yangtools.yang.common.Uint32;
47 import org.opendaylight.yangtools.yang.common.Uint64;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 @Deprecated
52 public class QueryByFilter {
53
54     private static final Logger LOG = LoggerFactory.getLogger(DataObjectAcessorPm.class);
55     private static final List<String> timestampValueNames = Arrays.asList("timestamp", "start", "end");
56
57     private static List<Sortorder> emptySortOrderList = new ArrayList<>();
58     private static List<Filter> emptyFilterList = new ArrayList<>();
59
60     // Derived from input
61     private long page;
62     private long pageSize;
63     private long fromPage;
64     private List<Filter> filterList;
65     private List<Sortorder> sortOrder;
66
67     /**
68      * Process input from RPC into Queries to database
69      *
70      * @param input Input from RPC, for test it could be null
71      */
72     public QueryByFilter(EntityInput input) {
73         page = -1;
74         pageSize = -1;
75         if (input != null) {
76             @Nullable
77             Pagination pagination = input.getPagination();
78             if (pagination != null) {
79                 @Nullable
80                 Uint64 pageOrNull = YangHelper2.getUint64(pagination.getPage());
81                 if (pageOrNull != null) {
82                     page = pageOrNull.longValue();
83                 }
84                 @Nullable
85                 Uint32 pageSizeOrNull = YangHelper2.getUint32(pagination.getSize());
86                 if (pageSizeOrNull != null) {
87                     pageSize = pageSizeOrNull.longValue();
88                 }
89             }
90         }
91         if (page < 0)
92             page = 1;
93         if (pageSize < 0)
94             pageSize = 1;
95
96         fromPage = (page - 1) * pageSize;
97         if (fromPage < 0 || pageSize > 10000)
98             throw new IllegalArgumentException("mismatching input parameters. From:" + fromPage + " size:" + pageSize);
99
100         filterList = input == null ? null : YangHelper.getList(input.getFilter());
101         if (filterList == null)
102             filterList = emptyFilterList;
103         sortOrder = input == null ? null : YangHelper.getList(input.getSortorder());
104         if (sortOrder == null)
105             sortOrder = emptySortOrderList;
106
107     }
108
109     public QueryBuilder getQueryBuilderByFilter() {
110         return getQueryBuilderByFilter("");
111     }
112
113     public QueryBuilder getQueryBuilderByFilter(String prefix) {
114         QueryBuilder queryBuilder = fromFilter(filterList, prefix).from(fromPage).size(pageSize);
115         setSortOrder(queryBuilder, sortOrder, prefix);
116         return queryBuilder;
117     }
118
119     public SearchRequest getSearchRequestByFilter(String nodeKey, String uuidKey, String index, String dataType,
120             boolean doFullsizeRequest) {
121         Filter nodeFilter = getFilter(filterList, nodeKey);
122         if (nodeFilter != null) {
123             SearchRequest request = new SearchRequest(index, dataType);
124             request.setQuery(QueryBuilders.matchQuery(nodeKey, nodeFilter.getFiltervalue())
125                     .setFullsizeRequest(doFullsizeRequest).aggregations(uuidKey).size(0));
126             return request;
127         } else {
128             String msg = "no nodename in filter found ";
129             LOG.debug(msg);
130             throw new IllegalArgumentException(msg);
131         }
132     }
133
134     public SearchRequest getSearchRequestAggregated(String aggregationKey, String index, String dataType,
135                                                     boolean doFullsizeRequest) {
136         Sortorder soNode = getSortOrder(sortOrder, aggregationKey);
137         SearchRequest request = new SearchRequest(index, dataType);
138         QueryBuilder query = null;
139         if (soNode != null) {
140             query = QueryBuilders.matchAllQuery().setFullsizeRequest(doFullsizeRequest)
141                     .aggregations(aggregationKey, convert(soNode.getSortorder())).size(0);
142         } else {
143             query = QueryBuilders.matchAllQuery().setFullsizeRequest(doFullsizeRequest).aggregations(aggregationKey).size(0);
144         }
145         request.setQuery(query);
146         return request;
147     }
148
149     public long getPage() {
150         return page;
151     }
152
153     public long getPageSize() {
154         return pageSize;
155     }
156
157     public long getPageStartIndex() {
158         return fromPage;
159     }
160
161     @Override
162     public String toString() {
163         return "QueryByFilter [page=" + page + ", pageSize=" + pageSize + ", fromPage=" + fromPage + ", filterList="
164                 + filterList + ", sortOrder=" + sortOrder + "]";
165     }
166
167     /*
168      * Private and static implementations
169      */
170     private static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder, String prefix) {
171         if (sortorder != null && !sortorder.isEmpty()) {
172             for (Sortorder so : sortorder) {
173                 query.sort(handlePrefix(prefix, so.getProperty()), convert(so.getSortorder()));
174             }
175         }
176         return query;
177     }
178
179     private static org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder convert(SortOrder sortOrder) {
180         return sortOrder == SortOrder.Ascending
181                 ? org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.ASCENDING
182                 : org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.DESCENDING;
183     }
184
185     private static Sortorder getSortOrder(@Nullable List<Sortorder> list, String prop) {
186         if (list == null) {
187             return null;
188         }
189         for (Sortorder o : list) {
190             if (prop.equals(o.getProperty())) {
191                 return o;
192             }
193         }
194         return null;
195     }
196
197     private static Filter getFilter(@Nullable List<Filter> list, String prop) {
198         if (list == null) {
199             return null;
200         }
201         for (Filter f : list) {
202             if (prop.equals(f.getProperty())) {
203                 return f;
204             }
205         }
206         return null;
207     }
208
209     private static String fillTimeStamp(String value) {
210         int idx = value.lastIndexOf("*");
211         final String REPLACE = "0000-00-00T00:00:00.0Z";
212         String s = value.substring(0, idx) + REPLACE.substring(idx);
213         if (Integer.parseInt(s.substring(5, 7)) == 0) {
214             s = s.substring(0, 5) + "01-" + s.substring(8);
215         }
216         if (Integer.parseInt(s.substring(8, 10)) == 0) {
217             s = s.substring(0, 8) + "01" + s.substring(10);
218         }
219
220         return s;
221     }
222
223     /**
224      * convert timestamp with ending placeholder in filter to elasticsearch filter e.g. 2017* => gte:
225      * 2017-01-01T00:00:00Z, lt:2018-01-01T00:00:00Z
226      *
227      * 201* => 2010-01... 2020 .. 2018-* => 2018-01... <=> 2019-01
228      *
229      */
230     private static @Nullable QueryBuilder fromTimestampSearchFilter(String property, String value) {
231         if (!value.endsWith("*")) {
232             return null;
233         }
234         int idx = value.lastIndexOf("*");
235         String lowerEnd = fillTimeStamp(value);
236         String upperEnd = null;
237         NetconfTimeStamp converter = NetconfTimeStampImpl.getConverter();
238         Date dt = null;
239         try {
240             dt = converter.getDateFromNetconf(lowerEnd);
241         } catch (Exception e) {
242
243         }
244         if (dt == null) {
245             return null;
246         }
247         // property.substring(0,idx)+REPLACE.substring(idx+1);
248         Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
249         c.setTime(dt);
250         int tmpvalue;
251         switch (idx) {
252             case 1: // (2*)
253                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1000);
254                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
255                 break;
256             case 2: // (20*)
257                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 100);
258                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
259                 break;
260             case 3: // (200*)
261                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 10);
262                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
263                 break;
264             case 4: // (2000*)
265             case 5: // (2000-*)
266                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
267                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
268                 break;
269             case 6: // switch 10 months (2000-0* or 2000-1*)
270                 tmpvalue = c.get(Calendar.MONTH);
271                 if (tmpvalue < 9) {
272                     c.set(Calendar.MONTH, 9);
273                 } else {
274                     c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
275                     c.set(Calendar.MONTH, 0);
276                 }
277                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
278
279                 break;
280             case 7: // switch one month (2018-01* or 2018-01-*)
281             case 8:
282                 c.add(Calendar.MONTH, 1);
283                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
284                 break;
285             case 9: // (2018-01-0*)
286                 tmpvalue = c.get(Calendar.DAY_OF_MONTH);
287                 if (tmpvalue == 1) {
288                     c.set(Calendar.DAY_OF_MONTH, 10);
289                 } else if (tmpvalue == 10) {
290                     c.set(Calendar.DAY_OF_MONTH, 20);
291                 } else if (tmpvalue == 20) {
292                     if (c.getActualMaximum(Calendar.DAY_OF_MONTH) < 30) {
293                         c.set(Calendar.DAY_OF_MONTH, 1);
294                         c.add(Calendar.MONTH, 1);
295                     } else {
296                         c.set(Calendar.DAY_OF_MONTH, 30);
297                     }
298                 } else if (tmpvalue == 30) {
299                     c.set(Calendar.DAY_OF_MONTH, 1);
300                     c.add(Calendar.MONTH, 1);
301                 } else {
302                     break;
303                 }
304                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
305                 break;
306             case 10: // (2018-01-01*)
307             case 11: // (2018-01-01T*)
308                 c.add(Calendar.DAY_OF_MONTH, 1);
309                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
310                 break;
311             case 12: // (2018-01-01T1*)
312                 tmpvalue = c.get(Calendar.HOUR_OF_DAY);
313                 if (tmpvalue == 20) {
314                     c.set(Calendar.HOUR_OF_DAY, 0);
315                     c.add(Calendar.DAY_OF_MONTH, 1);
316                 } else {
317                     c.add(Calendar.HOUR_OF_DAY, 10);
318                 }
319                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
320                 break;
321             case 13: // (2018-01-01T11*)
322             case 14: // (2018-01-01T11-*)
323                 c.add(Calendar.HOUR_OF_DAY, 1);
324                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
325                 break;
326             case 15: // (2018-01-01T11-3*)
327                 c.add(Calendar.MINUTE, 10);
328                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
329                 break;
330             case 16: // (2018-01-01T11-32*)
331             case 17: // (2018-01-01T11-32-*)
332                 c.add(Calendar.MINUTE, 1);
333                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
334                 break;
335             case 18: // (2018-01-01T11-32-1*)
336                 c.add(Calendar.SECOND, 10);
337                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
338                 break;
339             case 19: // (2018-01-01T11-32-11*)
340             case 20: // (2018-01-01T11-32-11.*)
341                 c.add(Calendar.SECOND, 1);
342                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
343                 break;
344
345             default:
346                 break;
347         }
348
349         if (upperEnd == null) {
350             return null;
351         }
352         return QueryBuilders.rangeQuery(property).gte(lowerEnd).lt(upperEnd);
353
354     }
355
356     private static List<String> collectValues(Filter filter) {
357         List<String> values = new ArrayList<>();
358         if (filter.getFiltervalue() != null) {
359             values.add(filter.getFiltervalue());
360         }
361         if (filter.getFiltervalues() != null) {
362             values.addAll(filter.getFiltervalues());
363         }
364         return values;
365     }
366
367     private static QueryBuilder fromFilter(@Nullable List<Filter> filters, String prefix) {
368         if (filters == null || filters.isEmpty()) {
369             return QueryBuilders.matchAllQuery();
370
371         } else if (filters.size() == 1) {
372             String property = filters.get(0).getProperty();
373             List<String> values = collectValues(filters.get(0));
374             if ("id".equals(property)) {
375                 property = "_id";
376             }
377             if (values.size() == 1) {
378                 return getSinglePropertyQuery(property, values.get(0), prefix);
379             } else {
380                 BoolQueryBuilder bquery = new BoolQueryBuilder();
381                 for (String v : values) {
382                     bquery.should(getSinglePropertyQuery(property, v, prefix));
383                 }
384                 return bquery;
385
386             }
387         } else {
388             BoolQueryBuilder query = new BoolQueryBuilder();
389             for (Filter fi : filters) {
390                 String p = fi.getProperty();
391                 List<String> values = collectValues(fi);
392                 if ("id".equals(p)) {
393                     p = "_id";
394                 }
395                 if (values.size() == 1) {
396                     query.must(getSinglePropertyQuery(p, values.get(0), prefix));
397                 } else {
398                     BoolQueryBuilder tmpQuery = QueryBuilders.boolQuery();
399                     for (String v : values) {
400                         tmpQuery.should(getSinglePropertyQuery(p, v, prefix));
401                     }
402                     query.must(tmpQuery);
403                 }
404             }
405             LOG.trace("Query result. {}", query.toJSON());
406             return query;
407         }
408     }
409
410     private static QueryBuilder getSinglePropertyQuery(String p, String v, String prefix) {
411         QueryBuilder query = null;
412         if (DbFilter.hasSearchParams(v)) {
413             if (p != null && timestampValueNames.contains(p.toLowerCase())) {
414                 query = fromTimestampSearchFilter(p, v);
415                 if (query == null) {
416                     query = QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v));
417                 }
418             } else {
419                 query = QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v));
420             }
421         } else if (DbFilter.isComparisonValid(v)) {
422             query = DbFilter.getRangeQuery(handlePrefix(prefix, p), v);
423             if (query == null) {
424                 query = QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
425             }
426         } else {
427             query = QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
428         }
429         return query;
430     }
431
432     private static String handlePrefix(String prefix, String p) {
433         return (prefix != null ? prefix : "") + p;
434     }
435
436 }