2 * ============LICENSE_START=======================================================
3 * ONAP : ccsdk features
4 * ================================================================================
5 * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.onap.ccsdk.features.sdnr.wt.dataprovider.data.rpctypehelper;
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.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;
51 public class QueryByFilter {
53 private static final Logger LOG = LoggerFactory.getLogger(DataObjectAcessorPm.class);
54 private static final List<String> timestampValueNames = Arrays.asList("timestamp", "start", "end");
56 private static List<Sortorder> emptySortOrderList = new ArrayList<>();
57 private static List<Filter> emptyFilterList = new ArrayList<>();
61 private long pageSize;
62 private long fromPage;
63 private List<Filter> filterList;
64 private List<Sortorder> sortOrder;
67 * Process input from RPC into Queries to database
69 * @param input Input from RPC, for test it could be null
71 public QueryByFilter(EntityInput input) {
76 Pagination pagination = input.getPagination();
77 if (pagination != null) {
79 Uint64 pageOrNull = YangHelper2.getUint64(pagination.getPage());
80 if (pageOrNull != null) {
81 page = pageOrNull.longValue();
84 Uint32 pageSizeOrNull = YangHelper2.getUint32(pagination.getSize());
85 if (pageSizeOrNull != null) {
86 pageSize = pageSizeOrNull.longValue();
95 fromPage = (page - 1) * pageSize;
96 if (fromPage < 0 || pageSize > 10000)
97 throw new IllegalArgumentException("mismatching input parameters. From:" + fromPage + " size:" + pageSize);
99 filterList = YangHelper.getList(input.getFilter());
100 if (filterList == null)
101 filterList = emptyFilterList;
102 sortOrder = YangHelper.getList(input.getSortorder());
103 if (sortOrder == null)
104 sortOrder = emptySortOrderList;
108 public QueryBuilder getQueryBuilderByFilter() {
109 return getQueryBuilderByFilter("");
112 public QueryBuilder getQueryBuilderByFilter(String prefix) {
113 QueryBuilder queryBuilder = fromFilter(filterList, prefix).from(fromPage).size(pageSize);
114 setSortOrder(queryBuilder, sortOrder, prefix);
118 public SearchRequest getSearchRequestByFilter(String nodeKey, String uuidKey, String index, String dataType) {
119 Filter nodeFilter = getFilter(filterList, nodeKey);
120 if (nodeFilter != null) {
121 SearchRequest request = new SearchRequest(index, dataType);
123 QueryBuilders.matchQuery(nodeKey, nodeFilter.getFiltervalue()).aggregations(uuidKey).size(0));
126 String msg = "no nodename in filter found ";
128 throw new IllegalArgumentException(msg);
132 public SearchRequest getSearchRequestBySortOrder(String nodeKey, String uuidKey, String index, String dataType) {
133 Sortorder soNode = getSortOrder(sortOrder, nodeKey);
134 SearchRequest request = new SearchRequest(index, dataType);
135 QueryBuilder query = null;
136 if (soNode != null) {
137 query = QueryBuilders.matchAllQuery().aggregations(nodeKey, convert(soNode.getSortorder())).size(0);
139 query = QueryBuilders.matchAllQuery().aggregations(nodeKey).size(0);
141 request.setQuery(query);
145 public long getPage() {
149 public long getPageSize() {
153 public long getPageStartIndex() {
158 public String toString() {
159 return "QueryByFilter [page=" + page + ", pageSize=" + pageSize + ", fromPage=" + fromPage + ", filterList="
160 + filterList + ", sortOrder=" + sortOrder + "]";
164 * Private and static implementations
166 private static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder, String prefix) {
167 if (sortorder != null && sortorder.size() > 0) {
168 for (Sortorder so : sortorder) {
169 query.sort(handlePrefix(prefix, so.getProperty()), convert(so.getSortorder()));
175 private static org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder convert(SortOrder sortOrder) {
176 return sortOrder == SortOrder.Ascending
177 ? org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.ASCENDING
178 : org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.DESCENDING;
181 private static Sortorder getSortOrder(@Nullable List<Sortorder> list, String prop) {
185 for (Sortorder o : list) {
186 if (prop.equals(o.getProperty())) {
193 private static Filter getFilter(@Nullable List<Filter> list, String prop) {
197 for (Filter f : list) {
198 if (prop.equals(f.getProperty())) {
205 private static String fillTimeStamp(String value) {
206 int idx = value.lastIndexOf("*");
207 final String REPLACE = "0000-00-00T00:00:00.0Z";
208 String s = value.substring(0, idx) + REPLACE.substring(idx);
209 if (Integer.parseInt(s.substring(5, 7)) == 0) {
210 s = s.substring(0, 5) + "01-" + s.substring(8);
212 if (Integer.parseInt(s.substring(8, 10)) == 0) {
213 s = s.substring(0, 8) + "01" + s.substring(10);
220 * convert timestamp with ending placeholder in filter to elasticsearch filter e.g. 2017* => gte:
221 * 2017-01-01T00:00:00Z, lt:2018-01-01T00:00:00Z
223 * 201* => 2010-01... 2020 .. 2018-* => 2018-01... <=> 2019-01
226 private static @Nullable QueryBuilder fromTimestampSearchFilter(String property, String value) {
227 if (!value.endsWith("*")) {
230 int idx = value.lastIndexOf("*");
231 String lowerEnd = fillTimeStamp(value);
232 String upperEnd = null;
233 NetconfTimeStamp converter = NetconfTimeStampImpl.getConverter();
236 dt = converter.getDateFromNetconf(lowerEnd);
237 } catch (Exception e) {
243 // property.substring(0,idx)+REPLACE.substring(idx+1);
244 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
249 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1000);
250 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
253 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 100);
254 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
257 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 10);
258 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
262 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
263 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
265 case 6: // switch 10 months (2000-0* or 2000-1*)
266 tmpvalue = c.get(Calendar.MONTH);
268 c.set(Calendar.MONTH, 9);
270 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
271 c.set(Calendar.MONTH, 0);
273 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
276 case 7: // switch one month (2018-01* or 2018-01-*)
278 c.add(Calendar.MONTH, 1);
279 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
281 case 9: // (2018-01-0*)
282 tmpvalue = c.get(Calendar.DAY_OF_MONTH);
284 c.set(Calendar.DAY_OF_MONTH, 10);
285 } else if (tmpvalue == 10) {
286 c.set(Calendar.DAY_OF_MONTH, 20);
287 } else if (tmpvalue == 20) {
288 if (c.getActualMaximum(Calendar.DAY_OF_MONTH) < 30) {
289 c.set(Calendar.DAY_OF_MONTH, 1);
290 c.add(Calendar.MONTH, 1);
292 c.set(Calendar.DAY_OF_MONTH, 30);
294 } else if (tmpvalue == 30) {
295 c.set(Calendar.DAY_OF_MONTH, 1);
296 c.add(Calendar.MONTH, 1);
300 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
302 case 10: // (2018-01-01*)
303 case 11: // (2018-01-01T*)
304 c.add(Calendar.DAY_OF_MONTH, 1);
305 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
307 case 12: // (2018-01-01T1*)
308 tmpvalue = c.get(Calendar.HOUR_OF_DAY);
309 if (tmpvalue == 20) {
310 c.set(Calendar.HOUR_OF_DAY, 0);
311 c.add(Calendar.DAY_OF_MONTH, 1);
313 c.add(Calendar.HOUR_OF_DAY, 10);
315 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
317 case 13: // (2018-01-01T11*)
318 case 14: // (2018-01-01T11-*)
319 c.add(Calendar.HOUR_OF_DAY, 1);
320 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
322 case 15: // (2018-01-01T11-3*)
323 c.add(Calendar.MINUTE, 10);
324 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
326 case 16: // (2018-01-01T11-32*)
327 case 17: // (2018-01-01T11-32-*)
328 c.add(Calendar.MINUTE, 1);
329 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
331 case 18: // (2018-01-01T11-32-1*)
332 c.add(Calendar.SECOND, 10);
333 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
335 case 19: // (2018-01-01T11-32-11*)
336 case 20: // (2018-01-01T11-32-11.*)
337 c.add(Calendar.SECOND, 1);
338 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
345 if (upperEnd == null) {
348 return QueryBuilders.rangeQuery(property).gte(lowerEnd).lt(upperEnd);
352 private static List<String> collectValues(Filter filter) {
353 List<String> values = new ArrayList<String>();
354 if (filter.getFiltervalue() != null) {
355 values.add(filter.getFiltervalue());
357 if (filter.getFiltervalues() != null) {
358 values.addAll(filter.getFiltervalues());
363 private static QueryBuilder fromFilter(@Nullable List<Filter> filters, String prefix) {
364 if (filters == null || filters.size() == 0) {
365 return QueryBuilders.matchAllQuery();
367 } else if (filters.size() == 1) {
368 String property = filters.get(0).getProperty();
369 List<String> values = collectValues(filters.get(0));
370 if ("id".equals(property)) {
373 if (values.size() == 1) {
374 return getSinglePropertyQuery(property, values.get(0), prefix);
376 BoolQueryBuilder bquery = new BoolQueryBuilder();
377 for (String v : values) {
378 bquery.should(getSinglePropertyQuery(property, v, prefix));
384 BoolQueryBuilder query = new BoolQueryBuilder();
385 for (Filter fi : filters) {
386 String p = fi.getProperty();
387 List<String> values = collectValues(fi);
388 if ("id".equals(p)) {
391 if (values.size() == 1) {
392 query.must(getSinglePropertyQuery(p, values.get(0), prefix));
394 BoolQueryBuilder tmpQuery = QueryBuilders.boolQuery();
395 for (String v : values) {
396 tmpQuery.should(getSinglePropertyQuery(p, v, prefix));
398 query.must(tmpQuery);
399 tmpQuery = QueryBuilders.boolQuery();
402 LOG.trace("Query result. {}", query.toJSON());
407 private static QueryBuilder getSinglePropertyQuery(String p, String v, String prefix) {
408 QueryBuilder query = null;
409 if (DbFilter.hasSearchParams(v)) {
410 if (p != null && timestampValueNames.contains(p.toLowerCase())) {
411 query = fromTimestampSearchFilter(p, v);
413 query = QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v));
416 query = QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v));
418 } else if (DbFilter.isComparisonValid(v)) {
419 query = DbFilter.getRangeQuery(handlePrefix(prefix, p), v);
421 query = QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
424 query = QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
429 private static String handlePrefix(String prefix, String p) {
430 return (prefix != null ? prefix : "") + p;