4354b16473c144ba09f6d7fbe1af4777951d4ed3
[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.sqldb.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.dataprovider.model.NetconfTimeStamp;
38 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl;
39 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.YangHelper2;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.EntityInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.SortOrder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Filter;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Pagination;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev201110.entity.input.Sortorder;
45 import org.opendaylight.yangtools.yang.common.Uint32;
46 import org.opendaylight.yangtools.yang.common.Uint64;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 public class SqlDBQueryByFilter {
51
52     private static final Logger LOG = LoggerFactory.getLogger(SqlDBQueryByFilter.class);
53     private static final List<String> timestampValueNames = Arrays.asList("timestamp", "time-stamp", "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 SqlDBQueryByFilter(EntityInput input) {
71         page = -1;
72         pageSize = -1;
73         if (input != null) {
74             @Nullable
75             Pagination pagination = input.getPagination();
76             if (pagination != null) {
77                 @Nullable Uint64 pageOrNull = YangHelper2.getUint64(pagination.getPage());
78                 if (pageOrNull != null) {
79                     page = pageOrNull.longValue();
80                 }
81                 @Nullable Uint32 pageSizeOrNull = YangHelper2.getUint32(pagination.getSize());
82                 if (pageSizeOrNull != null) {
83                     pageSize = pageSizeOrNull.longValue();
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 = YangHelper.getList(input.getFilter());
97         if (filterList == null)
98             filterList = emptyFilterList;
99         sortOrder = YangHelper.getList(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 long getPage() {
116         return page;
117     }
118
119     public long getPageSize() {
120         return pageSize;
121     }
122
123     public long getPageStartIndex() {
124         return fromPage;
125     }
126
127     @Override
128     public String toString() {
129         return "QueryByFilter [page=" + page + ", pageSize=" + pageSize + ", fromPage=" + fromPage + ", filterList="
130                 + filterList + ", sortOrder=" + sortOrder + "]";
131     }
132
133     /*
134      * Private and static implementations
135      */
136     private static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder, String prefix) {
137         if (sortorder != null && sortorder.size() > 0) {
138             for (Sortorder so : sortorder) {
139                 query.sort(handlePrefix(prefix, so.getProperty()), convert(so.getSortorder()));
140             }
141         }
142         return query;
143     }
144
145     private static org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder convert(SortOrder sortOrder) {
146         return sortOrder == SortOrder.Ascending
147                 ? org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.ASCENDING
148                 : org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.DESCENDING;
149     };
150
151     private static String fillTimeStamp(String value) {
152         int idx = value.lastIndexOf("*");
153         final String REPLACE = "0000-00-00T00:00:00.0Z";
154         String s = value.substring(0, idx) + REPLACE.substring(idx);
155         if (Integer.parseInt(s.substring(5, 7)) == 0) {
156             s = s.substring(0, 5) + "01-" + s.substring(8);
157         }
158         if (Integer.parseInt(s.substring(8, 10)) == 0) {
159             s = s.substring(0, 8) + "01" + s.substring(10);
160         }
161
162         return s;
163     }
164
165     /**
166      * convert timestamp with ending placeholder in filter to elasticsearch filter e.g. 2017* => gte:
167      * 2017-01-01T00:00:00Z, lt:2018-01-01T00:00:00Z
168      *
169      * 201* => 2010-01... 2020 .. 2018-* => 2018-01... <=> 2019-01
170      *
171      */
172     private static @Nullable QueryBuilder fromTimestampSearchFilter(String property, String value) {
173         if (!value.endsWith("*")) {
174             return null;
175         }
176         int idx = value.lastIndexOf("*");
177         String lowerEnd = fillTimeStamp(value);
178         String upperEnd = null;
179         NetconfTimeStamp converter = NetconfTimeStampImpl.getConverter();
180         Date dt = null;
181         try {
182             dt = converter.getDateFromNetconf(lowerEnd);
183         } catch (Exception e) {
184
185         }
186         if (dt == null) {
187             return null;
188         }
189         //        property.substring(0,idx)+REPLACE.substring(idx+1);
190         Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
191         c.setTime(dt);
192         int tmpvalue;
193         switch (idx) {
194             case 1: // (2*)
195                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1000);
196                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
197                 break;
198             case 2: // (20*)
199                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 100);
200                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
201                 break;
202             case 3: // (200*)
203                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 10);
204                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
205                 break;
206             case 4: // (2000*)
207             case 5: // (2000-*)
208                 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
209                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
210                 break;
211             case 6: // switch 10 months (2000-0* or 2000-1*)
212                 tmpvalue = c.get(Calendar.MONTH);
213                 if (tmpvalue < 9) {
214                     c.set(Calendar.MONTH, 9);
215                 } else {
216                     c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
217                     c.set(Calendar.MONTH, 0);
218                 }
219                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
220
221                 break;
222             case 7: // switch one month (2018-01* or 2018-01-*)
223             case 8:
224                 c.add(Calendar.MONTH, 1);
225                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
226                 break;
227             case 9: // (2018-01-0*)
228                 tmpvalue = c.get(Calendar.DAY_OF_MONTH);
229                 if (tmpvalue == 1) {
230                     c.set(Calendar.DAY_OF_MONTH, 10);
231                 } else if (tmpvalue == 10) {
232                     c.set(Calendar.DAY_OF_MONTH, 20);
233                 } else if (tmpvalue == 20) {
234                     if (c.getActualMaximum(Calendar.DAY_OF_MONTH) < 30) {
235                         c.set(Calendar.DAY_OF_MONTH, 1);
236                         c.add(Calendar.MONTH, 1);
237                     } else {
238                         c.set(Calendar.DAY_OF_MONTH, 30);
239                     }
240                 } else if (tmpvalue == 30) {
241                     c.set(Calendar.DAY_OF_MONTH, 1);
242                     c.add(Calendar.MONTH, 1);
243                 } else {
244                     break;
245                 }
246                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
247                 break;
248             case 10: // (2018-01-01*)
249             case 11: // (2018-01-01T*)
250                 c.add(Calendar.DAY_OF_MONTH, 1);
251                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
252                 break;
253             case 12: // (2018-01-01T1*)
254                 tmpvalue = c.get(Calendar.HOUR_OF_DAY);
255                 if (tmpvalue == 20) {
256                     c.set(Calendar.HOUR_OF_DAY, 0);
257                     c.add(Calendar.DAY_OF_MONTH, 1);
258                 } else {
259                     c.add(Calendar.HOUR_OF_DAY, 10);
260                 }
261                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
262                 break;
263             case 13: // (2018-01-01T11*)
264             case 14: // (2018-01-01T11-*)
265                 c.add(Calendar.HOUR_OF_DAY, 1);
266                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
267                 break;
268             case 15: // (2018-01-01T11-3*)
269                 c.add(Calendar.MINUTE, 10);
270                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
271                 break;
272             case 16: // (2018-01-01T11-32*)
273             case 17: // (2018-01-01T11-32-*)
274                 c.add(Calendar.MINUTE, 1);
275                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
276                 break;
277             case 18: // (2018-01-01T11-32-1*)
278                 c.add(Calendar.SECOND, 10);
279                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
280                 break;
281             case 19: // (2018-01-01T11-32-11*)
282             case 20: // (2018-01-01T11-32-11.*)
283                 c.add(Calendar.SECOND, 1);
284                 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
285                 break;
286
287             default:
288                 break;
289         }
290
291         if (upperEnd == null) {
292             return null;
293         }
294         return QueryBuilders.rangeQuery(property).gte(lowerEnd).lt(upperEnd);
295
296     }
297
298     private static QueryBuilder fromFilter(@Nullable List<Filter> filters, String prefix) {
299         if (filters == null || filters.size() == 0) {
300             return QueryBuilders.matchAllQuery();
301
302         } else if (filters.size() == 1) {
303             QueryBuilder query;
304             String p = filters.get(0).getProperty();
305             String v = filters.get(0).getFiltervalue();
306             if ("id".equals(p)) {
307                 p = "_id";
308             } else {
309                 //    v=v.toLowerCase();
310             }
311             if (DbFilter.hasSearchParams(v)) {
312                 if (p != null && timestampValueNames.contains(p.toLowerCase())) {
313                     query = fromTimestampSearchFilter(p, v);
314                     if (query != null) {
315                         return query;
316                     }
317                 }
318                 return QueryBuilders.regex(p, DbFilter.createDatabaseRegex(v));
319
320
321             } else if (DbFilter.isComparisonValid(v)) {
322                 RangeQueryBuilder q = DbFilter.getRangeQuery(handlePrefix(prefix, p), v);
323                 if (q != null) {
324                     return q;
325                 } else {
326                     return QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
327                 }
328             } else {
329                 return QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
330             }
331         } else {
332             BoolQueryBuilder query = new BoolQueryBuilder();
333             QueryBuilder tmpQuery;
334             for (Filter fi : filters) {
335                 String p = fi.getProperty();
336                 String v = fi.getFiltervalue();
337                 if ("id".equals(p)) {
338                     p = "_id";
339                 } else {
340                     //    v=v.toLowerCase();
341                 }
342                 if (DbFilter.hasSearchParams(v)) {
343                     if (p != null && timestampValueNames.contains(p.toLowerCase())) {
344                         tmpQuery = fromTimestampSearchFilter(p, v);
345                         if (tmpQuery != null) {
346                             query.must(tmpQuery);
347                         } else {
348                             query.must(QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v)));
349                         }
350                     } else {
351                         query.must(QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v)));
352                     }
353                 } else if (DbFilter.isComparisonValid(v)) {
354                     RangeQueryBuilder q = DbFilter.getRangeQuery(handlePrefix(prefix, p), v);
355                     if (q != null) {
356                         query.must(q);
357                     } else {
358                         query.must(QueryBuilders.matchQuery(handlePrefix(prefix, p), v));
359                     }
360                 } else {
361                     query.must(QueryBuilders.matchQuery(handlePrefix(prefix, p), v));
362                 }
363             }
364             LOG.trace("Query result. {}", query.toJSON());
365             return query;
366         }
367     }
368
369     private static String handlePrefix(String prefix, String p) {
370         return (prefix != null ? prefix : "") + p;
371     }
372
373 }