aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search')
-rw-r--r--src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/IllegalJsonValueException.java28
-rw-r--r--src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/JsonUtils.java104
-rw-r--r--src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/TemplateSearchHelper.java95
-rw-r--r--src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/handler/PrimitiveValueCriteriaBuilder.java103
-rw-r--r--src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/viewmodel/FlatTemplateContent.java45
-rw-r--r--src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/viewmodel/KeyValuePair.java40
6 files changed, 415 insertions, 0 deletions
diff --git a/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/IllegalJsonValueException.java b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/IllegalJsonValueException.java
new file mode 100644
index 0000000..d2c1c2a
--- /dev/null
+++ b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/IllegalJsonValueException.java
@@ -0,0 +1,28 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Simulator
+ * ================================================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.integration.simulators.nfsimulator.vesclient.template.search;
+
+public class IllegalJsonValueException extends IllegalArgumentException {
+
+ IllegalJsonValueException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/JsonUtils.java b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/JsonUtils.java
new file mode 100644
index 0000000..3d7c60d
--- /dev/null
+++ b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/JsonUtils.java
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Simulator
+ * ================================================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.integration.simulators.nfsimulator.vesclient.template.search;
+
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import org.bson.Document;
+
+/**
+ * This util flattens nested json and produces json with keys transformed to form of json path
+ * where default separator between parent object key and object key is ':'
+ * For easing searching of boolean values, they are converted to its string representation
+ */
+public class JsonUtils {
+
+ private static final String DEFAULT_PARENT_KEY_TO_OBJECT_KEY_SEPARATOR = ":";
+ private static final String SEED_PREFIX = "";
+ private static final Gson GSON = new Gson();
+
+ public JsonObject flatten(JsonObject original) {
+ return flattenWithPrefixedKeys(DEFAULT_PARENT_KEY_TO_OBJECT_KEY_SEPARATOR, original.deepCopy(), SEED_PREFIX, new JsonObject());
+ }
+
+ public JsonObject flatten(String parentKeyToKeySeparator, JsonObject original) {
+ return flattenWithPrefixedKeys(parentKeyToKeySeparator, original.deepCopy(), SEED_PREFIX, new JsonObject());
+ }
+
+ public Document flatten(Document original) {
+ return flatten(DEFAULT_PARENT_KEY_TO_OBJECT_KEY_SEPARATOR, original);
+ }
+
+ public Document flatten(String parentKeyToKeySeparator, Document original) {
+ JsonObject originalJsonObject = GSON.fromJson(original.toJson(), JsonObject.class);
+ JsonObject flattenedJson = flatten(parentKeyToKeySeparator, originalJsonObject);
+ return Document.parse(flattenedJson.toString());
+ }
+
+ private JsonObject flattenWithPrefixedKeys(String parentKeyToKeySeparator, JsonElement topLevelElem, String prefix, JsonObject acc) {
+ if (topLevelElem.isJsonPrimitive()) {
+ handleJsonPrimitive(topLevelElem, prefix, acc);
+ } else if (topLevelElem.isJsonArray()) {
+ handleJsonArray(parentKeyToKeySeparator, topLevelElem, prefix, acc);
+ } else if (topLevelElem.isJsonObject()) {
+ handleJsonObject(parentKeyToKeySeparator, topLevelElem, prefix, acc);
+ } else {
+ acc.add(prefix, topLevelElem.getAsJsonNull());
+ }
+ return acc.deepCopy();
+ }
+
+ private void handleJsonObject(String parentKeyToKeySeparator, JsonElement topLevelElem, String prefix, JsonObject acc) {
+ boolean isEmpty = true;
+ JsonObject thisToplevelObj = topLevelElem.getAsJsonObject();
+ for (String key : thisToplevelObj.keySet()) {
+ isEmpty = false;
+ String keyPrefix = String.format("%s%s%s", prefix, parentKeyToKeySeparator, key);
+ flattenWithPrefixedKeys(parentKeyToKeySeparator, thisToplevelObj.get(key), keyPrefix, acc);
+ }
+ if (isEmpty && !Strings.isNullOrEmpty(prefix)) {
+ acc.add(prefix, new JsonObject());
+ }
+ }
+
+ private void handleJsonArray(String parentKeyToKeySeparator, JsonElement topLevelElem, String prefix, JsonObject acc) {
+ JsonArray asJsonArray = topLevelElem.getAsJsonArray();
+ if (asJsonArray.size() == 0) {
+ acc.add(prefix, new JsonArray());
+ }
+ for (int i = 0; i < asJsonArray.size(); i++) {
+ flattenWithPrefixedKeys(parentKeyToKeySeparator, asJsonArray.get(i), String.format("%s[%s]", prefix, i), acc);
+ }
+ }
+
+ private void handleJsonPrimitive(JsonElement topLevelElem, String prefix, JsonObject acc) {
+ JsonPrimitive jsonPrimitive = topLevelElem.getAsJsonPrimitive();
+ if (jsonPrimitive.isBoolean()) {
+ acc.add(prefix, new JsonPrimitive(jsonPrimitive.getAsString()));
+ } else {
+ acc.add(prefix, topLevelElem.getAsJsonPrimitive());
+ }
+ }
+}
diff --git a/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/TemplateSearchHelper.java b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/TemplateSearchHelper.java
new file mode 100644
index 0000000..432b2d6
--- /dev/null
+++ b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/TemplateSearchHelper.java
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Simulator
+ * ================================================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.integration.simulators.nfsimulator.vesclient.template.search;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import org.onap.integration.simulators.nfsimulator.vesclient.template.search.handler.PrimitiveValueCriteriaBuilder;
+import org.onap.integration.simulators.nfsimulator.vesclient.template.search.viewmodel.FlatTemplateContent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@Component
+public class TemplateSearchHelper {
+ private static final String PARENT_TO_CHILD_KEY_SEPARATOR = ":"; //compliant with flat json stored in db
+ private static final String FLATTENED_JSON_KEY_REGEX = PARENT_TO_CHILD_KEY_SEPARATOR + "%s(?:(\\[[\\d]+\\]))?$";
+ private static final String FLATTENED_TEMPLATES_VIEW = "flatTemplatesView";
+
+ private MongoTemplate mongoTemplate;
+ private PrimitiveValueCriteriaBuilder criteriaBuilder;
+
+ @Autowired
+ public TemplateSearchHelper(MongoTemplate mongoTemplate) {
+ this.mongoTemplate = mongoTemplate;
+ this.criteriaBuilder = new PrimitiveValueCriteriaBuilder();
+ }
+
+ public List<String> getIdsOfDocumentMatchingCriteria(JsonObject jsonCriteria) {
+ if (isNullValuePresentInCriteria(jsonCriteria)) {
+ throw new IllegalJsonValueException("Null values in search criteria are not supported.");
+ }
+ Criteria mongoDialectCriteria = composeCriteria(jsonCriteria);
+ Query query = new Query(mongoDialectCriteria);
+ List<FlatTemplateContent> flatTemplateContents = mongoTemplate.find(query, FlatTemplateContent.class, FLATTENED_TEMPLATES_VIEW);
+ return flatTemplateContents
+ .stream()
+ .map(FlatTemplateContent::getId)
+ .collect(Collectors.toList());
+ }
+
+
+ private Criteria composeCriteria(JsonObject criteria) {
+ Criteria[] criteriaArr = criteria.entrySet()
+ .stream()
+ .map(this::mapEntryCriteriaWithRegex)
+ .toArray(Criteria[]::new);
+ return criteriaArr.length > 0 ? new Criteria().andOperator(criteriaArr) : new Criteria();
+ }
+
+ private Criteria mapEntryCriteriaWithRegex(Map.Entry<String, JsonElement> entry) {
+ Pattern primitiveOrArrayElemKeyRegex = getCaseInsensitive(String.format(FLATTENED_JSON_KEY_REGEX, entry.getKey()));
+ Criteria criteriaForJsonKey = Criteria.where("k").regex(primitiveOrArrayElemKeyRegex);
+ Criteria criteriaWithValue = criteriaBuilder.applyValueCriteriaBasedOnPrimitiveType(criteriaForJsonKey.and("v"), entry.getValue().getAsJsonPrimitive());
+ return Criteria.where("keyValues").elemMatch(criteriaWithValue);
+
+ }
+
+ private boolean isNullValuePresentInCriteria(JsonObject jsonObject) {
+ return jsonObject.entrySet()
+ .stream()
+ .map(Map.Entry::getValue)
+ .anyMatch(JsonElement::isJsonNull);
+ }
+
+ static Pattern getCaseInsensitive(String base) {
+ return Pattern.compile(base, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+ }
+}
+
+
diff --git a/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/handler/PrimitiveValueCriteriaBuilder.java b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/handler/PrimitiveValueCriteriaBuilder.java
new file mode 100644
index 0000000..7e5ae02
--- /dev/null
+++ b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/handler/PrimitiveValueCriteriaBuilder.java
@@ -0,0 +1,103 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Simulator
+ * ================================================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.integration.simulators.nfsimulator.vesclient.template.search.handler;
+
+import com.google.common.collect.Lists;
+import com.google.gson.JsonPrimitive;
+import org.springframework.data.mongodb.core.query.Criteria;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * This class is a helper class for constructing apropriate criteria for query send to mongodb based on type of value.
+ * Query is build to search mongodb for templates that contains key-value pairs that satisfy given criteria.
+ * Value is oftype JsonPrimitive, based on its primitive java type following criteria are build to get proper document:
+ * -for string - there is a regex expression that ignores every meta character inside passed argument and searches for exact literal match ignoring case;
+ * -for number - all numbers are treated as double (mongodb number type equivalent)
+ * -for boolean - exact match, used string representation of boolean in search
+ **/
+
+public class PrimitiveValueCriteriaBuilder {
+
+ private final List<ValueTypeHandler> typeHandlers;
+
+ public PrimitiveValueCriteriaBuilder() {
+ typeHandlers = Lists.newArrayList(new StringValueHandler(), new NumberValueHandler(), new BoolValueHandler());
+ }
+
+ public Criteria applyValueCriteriaBasedOnPrimitiveType(Criteria baseCriteria, JsonPrimitive jsonPrimitive) {
+ ValueTypeHandler typeHandler = typeHandlers.stream()
+ .filter(el -> el.isProperTypeHandler(jsonPrimitive))
+ .findFirst()
+ .orElseThrow(() ->
+ new IllegalArgumentException(String.format(
+ "Expected json primitive, but given value: %s is of type: %s and could not be decoded",
+ jsonPrimitive, jsonPrimitive.getClass().toString())));
+ return typeHandler.chainCriteriaForValue(baseCriteria, jsonPrimitive);
+ }
+
+ private interface ValueTypeHandler {
+ boolean isProperTypeHandler(JsonPrimitive value);
+
+ Criteria chainCriteriaForValue(Criteria criteria, JsonPrimitive value);
+ }
+
+ private class BoolValueHandler implements ValueTypeHandler {
+ public boolean isProperTypeHandler(JsonPrimitive value) {
+ return value.isBoolean();
+ }
+
+ public Criteria chainCriteriaForValue(Criteria criteria, JsonPrimitive value) {
+ return criteria.is(value.getAsString());
+ }
+
+ }
+
+ private class NumberValueHandler implements ValueTypeHandler {
+ public boolean isProperTypeHandler(JsonPrimitive value) {
+ return value.isNumber();
+ }
+
+ public Criteria chainCriteriaForValue(Criteria baseCriteria, JsonPrimitive value) {
+ return baseCriteria.is(value.getAsDouble());
+ }
+ }
+
+ private class StringValueHandler implements ValueTypeHandler {
+ public boolean isProperTypeHandler(JsonPrimitive value) {
+ return value.isString();
+ }
+
+ public Criteria chainCriteriaForValue(Criteria baseCriteria, JsonPrimitive value) {
+ return baseCriteria.regex(makeRegexCaseInsensitive(value.getAsString()));
+ }
+
+ private Pattern makeRegexCaseInsensitive(String base) {
+ String metaCharEscaped = convertToIgnoreMetaChars(base);
+ return Pattern.compile("^" + metaCharEscaped + "$", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+ }
+
+ private String convertToIgnoreMetaChars(String valueWithMetaChars) {
+ return Pattern.quote(valueWithMetaChars);
+ }
+ }
+}
diff --git a/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/viewmodel/FlatTemplateContent.java b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/viewmodel/FlatTemplateContent.java
new file mode 100644
index 0000000..9c9a39d
--- /dev/null
+++ b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/viewmodel/FlatTemplateContent.java
@@ -0,0 +1,45 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Simulator
+ * ================================================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.integration.simulators.nfsimulator.vesclient.template.search.viewmodel;
+
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import org.onap.integration.simulators.nfsimulator.vesclient.db.Row;
+
+import java.util.List;
+
+@Getter
+@NoArgsConstructor
+@ToString
+public class FlatTemplateContent extends Row {
+
+ private List<KeyValuePair> keyValues;
+
+
+ public FlatTemplateContent(String name, List<KeyValuePair> keyValues) {
+ this.setId(name);
+ this.keyValues = keyValues;
+ }
+}
+
+
diff --git a/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/viewmodel/KeyValuePair.java b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/viewmodel/KeyValuePair.java
new file mode 100644
index 0000000..9c9ca72
--- /dev/null
+++ b/src/main/java/org/onap/integration/simulators/nfsimulator/vesclient/template/search/viewmodel/KeyValuePair.java
@@ -0,0 +1,40 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Simulator
+ * ================================================================================
+ * Copyright (C) 2019 Nokia. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.integration.simulators.nfsimulator.vesclient.template.search.viewmodel;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+@Getter
+@ToString
+@NoArgsConstructor
+@AllArgsConstructor
+/**
+ * POJO for mongo structure after $objectToArray mapping where object consists of fields: k and v
+ */
+public class KeyValuePair {
+
+ private String key;
+ private String value;
+
+}