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