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;
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;
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.model.NetconfTimeStamp;
40 import org.onap.ccsdk.features.sdnr.wt.dataprovider.model.types.NetconfTimeStampImpl;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.EntityInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.SortOrder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Filter;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Pagination;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.data.provider.rev190801.entity.input.Sortorder;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
49 public class QueryByFilter {
51 private static final Logger LOG = LoggerFactory.getLogger(DataObjectAcessorPm.class);
52 private static final List<String> timestampValueNames = Arrays.asList("timestamp", "start", "end");
54 private static List<Sortorder> emptySortOrderList = new ArrayList<>();
55 private static List<Filter> emptyFilterList = new ArrayList<>();
59 private long pageSize;
60 private long fromPage;
61 private List<Filter> filterList;
62 private List<Sortorder> sortOrder;
65 * Process input from RPC into Queries to database
67 * @param input Input from RPC, for test it could be null
69 public QueryByFilter(EntityInput input) {
74 Pagination pagination = input.getPagination();
75 if (pagination != null) {
76 BigInteger pageOrNull = pagination.getPage();
77 if (pageOrNull != null) {
78 page = pageOrNull.longValue();
80 Long pageSizeOrNull = pagination.getSize();
81 if (pageSizeOrNull != null) {
82 pageSize = pageSizeOrNull;
91 fromPage = (page - 1) * pageSize;
92 if (fromPage < 0 || pageSize > 10000)
93 throw new IllegalArgumentException("mismatching input parameters. From:" + fromPage + " size:" + pageSize);
95 filterList = input.getFilter();
96 if (filterList == null)
97 filterList = emptyFilterList;
98 sortOrder = input.getSortorder();
99 if (sortOrder == null)
100 sortOrder = emptySortOrderList;
104 public QueryBuilder getQueryBuilderByFilter() {
105 return getQueryBuilderByFilter("");
108 public QueryBuilder getQueryBuilderByFilter(String prefix) {
109 QueryBuilder queryBuilder = fromFilter(filterList, prefix).from(fromPage).size(pageSize);
110 setSortOrder(queryBuilder, sortOrder, prefix);
114 public SearchRequest getSearchRequestByFilter(String nodeKey, String uuidKey, String index, String dataType) {
115 Filter nodeFilter = getFilter(filterList, nodeKey);
116 if (nodeFilter != null) {
117 SearchRequest request = new SearchRequest(index, dataType);
119 QueryBuilders.matchQuery(nodeKey, nodeFilter.getFiltervalue()).aggregations(uuidKey).size(0));
122 String msg = "no nodename in filter found ";
124 throw new IllegalArgumentException(msg);
128 public SearchRequest getSearchRequestBySortOrder(String nodeKey, String uuidKey, String index, String dataType) {
129 Sortorder soNode = getSortOrder(sortOrder, nodeKey);
130 SearchRequest request = new SearchRequest(index, dataType);
131 QueryBuilder query = null;
132 if (soNode != null) {
133 query = QueryBuilders.matchAllQuery().aggregations(nodeKey, convert(soNode.getSortorder())).size(0);
135 query = QueryBuilders.matchAllQuery().aggregations(nodeKey).size(0);
137 request.setQuery(query);
141 public long getPage() {
145 public long getPageSize() {
149 public long getPageStartIndex() {
154 public String toString() {
155 return "QueryByFilter [page=" + page + ", pageSize=" + pageSize + ", fromPage=" + fromPage + ", filterList="
156 + filterList + ", sortOrder=" + sortOrder + "]";
160 * Private and static implementations
162 private static QueryBuilder setSortOrder(QueryBuilder query, @Nullable List<Sortorder> sortorder, String prefix) {
163 if (sortorder != null && sortorder.size() > 0) {
164 for (Sortorder so : sortorder) {
165 query.sort(handlePrefix(prefix, so.getProperty()), convert(so.getSortorder()));
171 private static org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder convert(SortOrder sortOrder) {
172 return sortOrder == SortOrder.Ascending
173 ? org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.ASCENDING
174 : org.onap.ccsdk.features.sdnr.wt.common.database.queries.SortOrder.DESCENDING;
177 private static Sortorder getSortOrder(@Nullable List<Sortorder> list, String prop) {
181 for (Sortorder o : list) {
182 if (prop.equals(o.getProperty())) {
189 private static Filter getFilter(@Nullable List<Filter> list, String prop) {
193 for (Filter f : list) {
194 if (prop.equals(f.getProperty())) {
201 private static String fillTimeStamp(String value) {
202 int idx = value.lastIndexOf("*");
203 final String REPLACE = "0000-00-00T00:00:00.0Z";
204 String s = value.substring(0, idx) + REPLACE.substring(idx);
205 if (Integer.parseInt(s.substring(5, 7)) == 0) {
206 s = s.substring(0, 5) + "01-" + s.substring(8);
208 if (Integer.parseInt(s.substring(8, 10)) == 0) {
209 s = s.substring(0, 8) + "01" + s.substring(10);
216 * convert timestamp with ending placeholder in filter to elasticsearch filter e.g. 2017* => gte:
217 * 2017-01-01T00:00:00Z, lt:2018-01-01T00:00:00Z
219 * 201* => 2010-01... 2020 .. 2018-* => 2018-01... <=> 2019-01
222 private static @Nullable QueryBuilder fromTimestampSearchFilter(String property, String value) {
223 if (!value.endsWith("*")) {
226 int idx = value.lastIndexOf("*");
227 String lowerEnd = fillTimeStamp(value);
228 String upperEnd = null;
229 NetconfTimeStamp converter = NetconfTimeStampImpl.getConverter();
232 dt = converter.getDateFromNetconf(lowerEnd);
233 } catch (Exception e) {
239 // property.substring(0,idx)+REPLACE.substring(idx+1);
240 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
245 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1000);
246 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
249 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 100);
250 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
253 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 10);
254 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
258 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
259 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
261 case 6: // switch 10 months (2000-0* or 2000-1*)
262 tmpvalue = c.get(Calendar.MONTH);
264 c.set(Calendar.MONTH, 9);
266 c.set(Calendar.YEAR, c.get(Calendar.YEAR) + 1);
267 c.set(Calendar.MONTH, 0);
269 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
272 case 7: // switch one month (2018-01* or 2018-01-*)
274 c.add(Calendar.MONTH, 1);
275 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
277 case 9: // (2018-01-0*)
278 tmpvalue = c.get(Calendar.DAY_OF_MONTH);
280 c.set(Calendar.DAY_OF_MONTH, 10);
281 } else if (tmpvalue == 10) {
282 c.set(Calendar.DAY_OF_MONTH, 20);
283 } else if (tmpvalue == 20) {
284 if (c.getActualMaximum(Calendar.DAY_OF_MONTH) < 30) {
285 c.set(Calendar.DAY_OF_MONTH, 1);
286 c.add(Calendar.MONTH, 1);
288 c.set(Calendar.DAY_OF_MONTH, 30);
290 } else if (tmpvalue == 30) {
291 c.set(Calendar.DAY_OF_MONTH, 1);
292 c.add(Calendar.MONTH, 1);
296 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
298 case 10: // (2018-01-01*)
299 case 11: // (2018-01-01T*)
300 c.add(Calendar.DAY_OF_MONTH, 1);
301 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
303 case 12: // (2018-01-01T1*)
304 tmpvalue = c.get(Calendar.HOUR_OF_DAY);
305 if (tmpvalue == 20) {
306 c.set(Calendar.HOUR_OF_DAY, 0);
307 c.add(Calendar.DAY_OF_MONTH, 1);
309 c.add(Calendar.HOUR_OF_DAY, 10);
311 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
313 case 13: // (2018-01-01T11*)
314 case 14: // (2018-01-01T11-*)
315 c.add(Calendar.HOUR_OF_DAY, 1);
316 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
318 case 15: // (2018-01-01T11-3*)
319 c.add(Calendar.MINUTE, 10);
320 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
322 case 16: // (2018-01-01T11-32*)
323 case 17: // (2018-01-01T11-32-*)
324 c.add(Calendar.MINUTE, 1);
325 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
327 case 18: // (2018-01-01T11-32-1*)
328 c.add(Calendar.SECOND, 10);
329 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
331 case 19: // (2018-01-01T11-32-11*)
332 case 20: // (2018-01-01T11-32-11.*)
333 c.add(Calendar.SECOND, 1);
334 upperEnd = converter.getTimeStampAsNetconfString(c.getTime());
341 if (upperEnd == null) {
344 return QueryBuilders.rangeQuery(property).gte(lowerEnd).lt(upperEnd);
348 private static QueryBuilder fromFilter(@Nullable List<Filter> filters, String prefix) {
349 if (filters == null || filters.size() == 0) {
350 return QueryBuilders.matchAllQuery();
352 } else if (filters.size() == 1) {
354 String p = filters.get(0).getProperty();
355 String v = filters.get(0).getFiltervalue();
356 if ("id".equals(p)) {
359 // v=v.toLowerCase();
361 if (DbFilter.hasSearchParams(v)) {
362 if (p != null && timestampValueNames.contains(p.toLowerCase())) {
363 query = fromTimestampSearchFilter(p, v);
368 return QueryBuilders.regex(p, DbFilter.createDatabaseRegex(v));
371 } else if (DbFilter.isComparisonValid(v)) {
372 RangeQueryBuilder q = DbFilter.getRangeQuery(handlePrefix(prefix, p), v);
376 return QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
379 return QueryBuilders.matchQuery(handlePrefix(prefix, p), v);
382 BoolQueryBuilder query = new BoolQueryBuilder();
383 QueryBuilder tmpQuery;
384 for (Filter fi : filters) {
385 String p = fi.getProperty();
386 String v = fi.getFiltervalue();
387 if ("id".equals(p)) {
390 // v=v.toLowerCase();
392 if (DbFilter.hasSearchParams(v)) {
393 if (p != null && timestampValueNames.contains(p.toLowerCase())) {
394 tmpQuery = fromTimestampSearchFilter(p, v);
395 if (tmpQuery != null) {
396 query.must(tmpQuery);
398 query.must(QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v)));
401 query.must(QueryBuilders.regex(handlePrefix(prefix, p), DbFilter.createDatabaseRegex(v)));
403 } else if (DbFilter.isComparisonValid(v)) {
404 RangeQueryBuilder q = DbFilter.getRangeQuery(handlePrefix(prefix, p), v);
408 query.must(QueryBuilders.matchQuery(handlePrefix(prefix, p), v));
411 query.must(QueryBuilders.matchQuery(handlePrefix(prefix, p), v));
414 LOG.trace("Query result. {}", query.toJSON());
419 private static String handlePrefix(String prefix, String p) {
420 return (prefix != null ? prefix : "") + p;