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.database.elasticsearch.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.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;
52 public class QueryByFilter {
54 private static final Logger LOG = LoggerFactory.getLogger(DataObjectAcessorPm.class);
55 private static final List<String> timestampValueNames = Arrays.asList("timestamp", "start", "end");
57 private static List<Sortorder> emptySortOrderList = new ArrayList<>();
58 private static List<Filter> emptyFilterList = new ArrayList<>();
62 private long pageSize;
63 private long fromPage;
64 private List<Filter> filterList;
65 private List<Sortorder> sortOrder;
68 * Process input from RPC into Queries to database
70 * @param input Input from RPC, for test it could be null
72 public QueryByFilter(EntityInput input) {
77 Pagination pagination = input.getPagination();
78 if (pagination != null) {
80 Uint64 pageOrNull = YangHelper2.getUint64(pagination.getPage());
81 if (pageOrNull != null) {
82 page = pageOrNull.longValue();
85 Uint32 pageSizeOrNull = YangHelper2.getUint32(pagination.getSize());
86 if (pageSizeOrNull != null) {
87 pageSize = pageSizeOrNull.longValue();
96 fromPage = (page - 1) * pageSize;
97 if (fromPage < 0 || pageSize > 10000)
98 throw new IllegalArgumentException("mismatching input parameters. From:" + fromPage + " size:" + pageSize);
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;
109 public QueryBuilder getQueryBuilderByFilter() {
110 return getQueryBuilderByFilter("");
113 public QueryBuilder getQueryBuilderByFilter(String prefix) {
114 QueryBuilder queryBuilder = fromFilter(filterList, prefix).from(fromPage).size(pageSize);
115 setSortOrder(queryBuilder, sortOrder, prefix);
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));
128 String msg = "no nodename in filter found ";
130 throw new IllegalArgumentException(msg);
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);
143 query = QueryBuilders.matchAllQuery().setFullsizeRequest(doFullsizeRequest).aggregations(aggregationKey).size(0);
145 request.setQuery(query);
149 public long getPage() {
153 public long getPageSize() {
157 public long getPageStartIndex() {
162 public String toString() {
163 return "QueryByFilter [page=" + page + ", pageSize=" + pageSize + ", fromPage=" + fromPage + ", filterList="
164 + filterList + ", sortOrder=" + sortOrder + "]";
168 * Private and static implementations
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()));
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;
185 private static Sortorder getSortOrder(@Nullable List<Sortorder> list, String prop) {
189 for (Sortorder o : list) {
190 if (prop.equals(o.getProperty())) {
197 private static Filter getFilter(@Nullable List<Filter> list, String prop) {
201 for (Filter f : list) {
202 if (prop.equals(f.getProperty())) {
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);
216 if (Integer.parseInt(s.substring(8, 10)) == 0) {
217 s = s.substring(0, 8) + "01" + s.substring(10);
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
227 * 201* => 2010-01... 2020 .. 2018-* => 2018-01... <=> 2019-01
230 private static @Nullable QueryBuilder fromTimestampSearchFilter(String property, String value) {
231 if (!value.endsWith("*")) {
234 int idx = value.lastIndexOf("*");
235 String lowerEnd = fillTimeStamp(value);
236 String upperEnd = null;
237 NetconfTimeStamp converter = NetconfTimeStampImpl.getConverter();
240 dt = converter.getDateFromNetconf(lowerEnd);
241 } catch (Exception e) {
247 // property.substring(0,idx)+REPLACE.substring(idx+1);
248 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
253 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1000);
254 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
257 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 100);
258 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
261 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 10);
262 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
266 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
267 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
269 case 6: // switch 10 months (2000-0* or 2000-1*)
270 tmpvalue = c.get(Calendar.MONTH);
272 c.set(Calendar.MONTH, 9);
274 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
275 c.set(Calendar.MONTH, 0);
277 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
280 case 7: // switch one month (2018-01* or 2018-01-*)
282 c.add(Calendar.MONTH, 1);
283 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
285 case 9: // (2018-01-0*)
286 tmpvalue = c.get(Calendar.DAY_OF_MONTH);
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);
296 c.set(Calendar.DAY_OF_MONTH, 30);
298 } else if (tmpvalue == 30) {
299 c.set(Calendar.DAY_OF_MONTH, 1);
300 c.add(Calendar.MONTH, 1);
304 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
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());
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);
317 c.add(Calendar.HOUR_OF_DAY, 10);
319 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
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());
326 case 15: // (2018-01-01T11-3*)
327 c.add(Calendar.MINUTE, 10);
328 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
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());
335 case 18: // (2018-01-01T11-32-1*)
336 c.add(Calendar.SECOND, 10);
337 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
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());
349 if (upperEnd == null) {
352 return QueryBuilders.rangeQuery(property).gte(lowerEnd).lt(upperEnd);
356 private static List<String> collectValues(Filter filter) {
357 List<String> values = new ArrayList<>();
358 if (filter.getFiltervalue() != null) {
359 values.add(filter.getFiltervalue());
361 if (filter.getFiltervalues() != null) {
362 values.addAll(filter.getFiltervalues());
367 private static QueryBuilder fromFilter(@Nullable List<Filter> filters, String prefix) {
368 if (filters == null || filters.isEmpty()) {
369 return QueryBuilders.matchAllQuery();
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)) {
377 if (values.size() == 1) {
378 return getSinglePropertyQuery(property, values.get(0), prefix);
380 BoolQueryBuilder bquery = new BoolQueryBuilder();
381 for (String v : values) {
382 bquery.should(getSinglePropertyQuery(property, v, prefix));
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)) {
395 if (values.size() == 1) {
396 query.must(getSinglePropertyQuery(p, values.get(0), prefix));
398 BoolQueryBuilder tmpQuery = QueryBuilders.boolQuery();
399 for (String v : values) {
400 tmpQuery.should(getSinglePropertyQuery(p, v, prefix));
402 query.must(tmpQuery);
405 LOG.trace("Query result. {}", query.toJSON());
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);
416 query = QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v));
419 query = QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v));
421 } else if (DbFilter.isComparisonValid(v)) {
422 query = DbFilter.getRangeQuery(handlePrefix(prefix, p), v);
424 query = QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
427 query = QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
432 private static String handlePrefix(String prefix, String p) {
433 return (prefix != null ? prefix : "") + p;