09e48197a7d3a368a2522e85070c7279fd569fa4
[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.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.queries.RangeQueryBuilder;
37 import org.onap.ccsdk.features.sdnr.wt.common.database.requests.SearchRequest;
38 import org.onap.ccsdk.features.sdnr.wt.dataprovider.data.acessor.DataObjectAcessorPm;
39 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.NetconfTimeStamp;
40 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl;
41 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.YangHelper2;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.EntityInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.SortOrder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Filter;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Pagination;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Sortorder;
47 import org.opendaylight.yangtools.yang.common.Uint32;
48 import org.opendaylight.yangtools.yang.common.Uint64;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
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 Uint64 pageOrNull = YangHelper2.getUint64(pagination.getPage());
80                 if (pageOrNull != null) {
81                     page = pageOrNull.longValue();
82                 }
83                 @Nullable Uint32 pageSizeOrNull = YangHelper2.getUint32(pagination.getSize());
84                 if (pageSizeOrNull != null) {
85                     pageSize = pageSizeOrNull.longValue();
86                 }
87             }
88         }
89         if (page < 0)
90             page = 1;
91         if (pageSize < 0)
92             pageSize = 1;
93
94         fromPage = (page - 1) * pageSize;
95         if (fromPage < 0 || pageSize > 10000)
96             throw new IllegalArgumentException("mismatching input parameters. From:" + fromPage + " size:" + pageSize);
97
98         filterList = YangHelper.getList(input.getFilter());
99         if (filterList == null)
100             filterList = emptyFilterList;
101         sortOrder = YangHelper.getList(input.getSortorder());
102         if (sortOrder == null)
103             sortOrder = emptySortOrderList;
104
105     }
106
107     public QueryBuilder getQueryBuilderByFilter() {
108         return getQueryBuilderByFilter("");
109     }
110
111     public QueryBuilder getQueryBuilderByFilter(String prefix) {
112         QueryBuilder queryBuilder = fromFilter(filterList, prefix).from(fromPage).size(pageSize);
113         setSortOrder(queryBuilder, sortOrder, prefix);
114         return queryBuilder;
115     }
116
117     public SearchRequest getSearchRequestByFilter(String nodeKey, String uuidKey, String index, String dataType) {
118         Filter nodeFilter = getFilter(filterList, nodeKey);
119         if (nodeFilter != null) {
120             SearchRequest request = new SearchRequest(index, dataType);
121             request.setQuery(
122                     QueryBuilders.matchQuery(nodeKey, nodeFilter.getFiltervalue()).aggregations(uuidKey).size(0));
123             return request;
124         } else {
125             String msg = "no nodename in filter found ";
126             LOG.debug(msg);
127             throw new IllegalArgumentException(msg);
128         }
129     }
130
131     public SearchRequest getSearchRequestBySortOrder(String nodeKey, String uuidKey, String index, String dataType) {
132         Sortorder soNode = getSortOrder(sortOrder, nodeKey);
133         SearchRequest request = new SearchRequest(index, dataType);
134         QueryBuilder query = null;
135         if (soNode != null) {
136             query = QueryBuilders.matchAllQuery().aggregations(nodeKey, convert(soNode.getSortorder())).size(0);
137         } else {
138             query = QueryBuilders.matchAllQuery().aggregations(nodeKey).size(0);
139         }
140         request.setQuery(query);
141         return request;
142     }
143
144     public long getPage() {
145         return page;
146     }
147
148     public long getPageSize() {
149         return pageSize;
150     }
151
152     public long getPageStartIndex() {
153         return fromPage;
154     }
155
156     @Override
157     public String toString() {
158         return "QueryByFilter [page=" + page + ", pageSize=" + pageSize + ", fromPage=" + fromPage + ", filterList="
159                 + filterList + ", sortOrder=" + sortOrder + "]";
160     }
161
162     /*
163      * Private and static implementations
164      */
165     private static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder, String prefix) {
166         if (sortorder != null && sortorder.size() > 0) {
167             for (Sortorder so : sortorder) {
168                 query.sort(handlePrefix(prefix, so.getProperty()), convert(so.getSortorder()));
169             }
170         }
171         return query;
172     }
173
174     private static org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder convert(SortOrder sortOrder) {
175         return sortOrder == SortOrder.Ascending
176                 ? org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.ASCENDING
177                 : org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.DESCENDING;
178     };
179
180     private static Sortorder getSortOrder(@Nullable List<Sortorder> list, String prop) {
181         if (list == null) {
182             return null;
183         }
184         for (Sortorder o : list) {
185             if (prop.equals(o.getProperty())) {
186                 return o;
187             }
188         }
189         return null;
190     }
191
192     private static Filter getFilter(@Nullable List<Filter> list, String prop) {
193         if (list == null) {
194             return null;
195         }
196         for (Filter f : list) {
197             if (prop.equals(f.getProperty())) {
198                 return f;
199             }
200         }
201         return null;
202     }
203
204     private static String fillTimeStamp(String value) {
205         int idx = value.lastIndexOf("*");
206         final String REPLACE = "0000-00-00T00:00:00.0Z";
207         String s = value.substring(0, idx) + REPLACE.substring(idx);
208         if (Integer.parseInt(s.substring(5, 7)) == 0) {
209             s = s.substring(0, 5) + "01-" + s.substring(8);
210         }
211         if (Integer.parseInt(s.substring(8, 10)) == 0) {
212             s = s.substring(0, 8) + "01" + s.substring(10);
213         }
214
215         return s;
216     }
217
218     /**
219      * convert timestamp with ending placeholder in filter to elasticsearch filter e.g. 2017* => gte:
220      * 2017-01-01T00:00:00Z, lt:2018-01-01T00:00:00Z
221      *
222      * 201* => 2010-01... 2020 .. 2018-* => 2018-01... <=> 2019-01
223      *
224      */
225     private static @Nullable QueryBuilder fromTimestampSearchFilter(String property, String value) {
226         if (!value.endsWith("*")) {
227             return null;
228         }
229         int idx = value.lastIndexOf("*");
230         String lowerEnd = fillTimeStamp(value);
231         String upperEnd = null;
232         NetconfTimeStamp converter = NetconfTimeStampImpl.getConverter();
233         Date dt = null;
234         try {
235             dt = converter.getDateFromNetconf(lowerEnd);
236         } catch (Exception e) {
237
238         }
239         if (dt == null) {
240             return null;
241         }
242         //        property.substring(0,idx)+REPLACE.substring(idx+1);
243         Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
244         c.setTime(dt);
245         int tmpvalue;
246         switch (idx) {
247             case 1: // (2*)
248                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1000);
249                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
250                 break;
251             case 2: // (20*)
252                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 100);
253                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
254                 break;
255             case 3: // (200*)
256                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 10);
257                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
258                 break;
259             case 4: // (2000*)
260             case 5: // (2000-*)
261                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
262                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
263                 break;
264             case 6: // switch 10 months (2000-0* or 2000-1*)
265                 tmpvalue = c.get(Calendar.MONTH);
266                 if (tmpvalue < 9) {
267                     c.set(Calendar.MONTH, 9);
268                 } else {
269                     c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
270                     c.set(Calendar.MONTH, 0);
271                 }
272                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
273
274                 break;
275             case 7: // switch one month (2018-01* or 2018-01-*)
276             case 8:
277                 c.add(Calendar.MONTH, 1);
278                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
279                 break;
280             case 9: // (2018-01-0*)
281                 tmpvalue = c.get(Calendar.DAY_OF_MONTH);
282                 if (tmpvalue == 1) {
283                     c.set(Calendar.DAY_OF_MONTH, 10);
284                 } else if (tmpvalue == 10) {
285                     c.set(Calendar.DAY_OF_MONTH, 20);
286                 } else if (tmpvalue == 20) {
287                     if (c.getActualMaximum(Calendar.DAY_OF_MONTH) < 30) {
288                         c.set(Calendar.DAY_OF_MONTH, 1);
289                         c.add(Calendar.MONTH, 1);
290                     } else {
291                         c.set(Calendar.DAY_OF_MONTH, 30);
292                     }
293                 } else if (tmpvalue == 30) {
294                     c.set(Calendar.DAY_OF_MONTH, 1);
295                     c.add(Calendar.MONTH, 1);
296                 } else {
297                     break;
298                 }
299                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
300                 break;
301             case 10: // (2018-01-01*)
302             case 11: // (2018-01-01T*)
303                 c.add(Calendar.DAY_OF_MONTH, 1);
304                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
305                 break;
306             case 12: // (2018-01-01T1*)
307                 tmpvalue = c.get(Calendar.HOUR_OF_DAY);
308                 if (tmpvalue == 20) {
309                     c.set(Calendar.HOUR_OF_DAY, 0);
310                     c.add(Calendar.DAY_OF_MONTH, 1);
311                 } else {
312                     c.add(Calendar.HOUR_OF_DAY, 10);
313                 }
314                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
315                 break;
316             case 13: // (2018-01-01T11*)
317             case 14: // (2018-01-01T11-*)
318                 c.add(Calendar.HOUR_OF_DAY, 1);
319                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
320                 break;
321             case 15: // (2018-01-01T11-3*)
322                 c.add(Calendar.MINUTE, 10);
323                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
324                 break;
325             case 16: // (2018-01-01T11-32*)
326             case 17: // (2018-01-01T11-32-*)
327                 c.add(Calendar.MINUTE, 1);
328                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
329                 break;
330             case 18: // (2018-01-01T11-32-1*)
331                 c.add(Calendar.SECOND, 10);
332                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
333                 break;
334             case 19: // (2018-01-01T11-32-11*)
335             case 20: // (2018-01-01T11-32-11.*)
336                 c.add(Calendar.SECOND, 1);
337                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
338                 break;
339
340             default:
341                 break;
342         }
343
344         if (upperEnd == null) {
345             return null;
346         }
347         return QueryBuilders.rangeQuery(property).gte(lowerEnd).lt(upperEnd);
348
349     }
350
351     private static QueryBuilder fromFilter(@Nullable List<Filter> filters, String prefix) {
352         if (filters == null || filters.size() == 0) {
353             return QueryBuilders.matchAllQuery();
354
355         } else if (filters.size() == 1) {
356             QueryBuilder query;
357             String p = filters.get(0).getProperty();
358             String v = filters.get(0).getFiltervalue();
359             if ("id".equals(p)) {
360                 p = "_id";
361             } else {
362                 //    v=v.toLowerCase();
363             }
364             if (DbFilter.hasSearchParams(v)) {
365                 if (p != null && timestampValueNames.contains(p.toLowerCase())) {
366                     query = fromTimestampSearchFilter(p, v);
367                     if (query != null) {
368                         return query;
369                     }
370                 }
371                 return QueryBuilders.regex(p, DbFilter.createDatabaseRegex(v));
372
373
374             } else if (DbFilter.isComparisonValid(v)) {
375                 RangeQueryBuilder q = DbFilter.getRangeQuery(handlePrefix(prefix, p), v);
376                 if (q != null) {
377                     return q;
378                 } else {
379                     return QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
380                 }
381             } else {
382                 return QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
383             }
384         } else {
385             BoolQueryBuilder query = new BoolQueryBuilder();
386             QueryBuilder tmpQuery;
387             for (Filter fi : filters) {
388                 String p = fi.getProperty();
389                 String v = fi.getFiltervalue();
390                 if ("id".equals(p)) {
391                     p = "_id";
392                 } else {
393                     //    v=v.toLowerCase();
394                 }
395                 if (DbFilter.hasSearchParams(v)) {
396                     if (p != null && timestampValueNames.contains(p.toLowerCase())) {
397                         tmpQuery = fromTimestampSearchFilter(p, v);
398                         if (tmpQuery != null) {
399                             query.must(tmpQuery);
400                         } else {
401                             query.must(QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v)));
402                         }
403                     } else {
404                         query.must(QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v)));
405                     }
406                 } else if (DbFilter.isComparisonValid(v)) {
407                     RangeQueryBuilder q = DbFilter.getRangeQuery(handlePrefix(prefix, p), v);
408                     if (q != null) {
409                         query.must(q);
410                     } else {
411                         query.must(QueryBuilders.matchQuery(handlePrefix(prefix, p), v));
412                     }
413                 } else {
414                     query.must(QueryBuilders.matchQuery(handlePrefix(prefix, p), v));
415                 }
416             }
417             LOG.trace("Query result. {}", query.toJSON());
418             return query;
419         }
420     }
421
422     private static String handlePrefix(String prefix, String p) {
423         return (prefix != null ? prefix : "") + p;
424     }
425
426 }