2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.aai.serialization.queryformats;
23 import com.google.gson.JsonArray;
24 import com.google.gson.JsonElement;
25 import com.google.gson.JsonObject;
26 import org.apache.tinkerpop.gremlin.process.traversal.Path;
27 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
28 import org.apache.tinkerpop.gremlin.structure.Vertex;
29 import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported;
30 import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
36 public abstract class MultiFormatMapper implements FormatMapper {
38 Logger logger = LoggerFactory.getLogger(MultiFormatMapper.class);
40 protected boolean isTree = false;
43 public Optional<JsonObject> formatObject(Object input)
44 throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported {
45 if (input instanceof Vertex) {
46 logger.debug("Formatting vertex object");
47 return this.getJsonFromVertex((Vertex) input);
48 } else if (input instanceof Tree) {
49 logger.debug("Formatting tree object");
51 return this.getRelatedNodesFromTree((Tree<?>) input, null);
53 return this.getJsonFromTree((Tree<?>) input);
55 } else if (input instanceof Path) {
56 logger.debug("Formatting path object");
57 return this.getJsonFromPath((Path) input);
59 throw new AAIFormatQueryResultFormatNotSupported();
64 public Optional<JsonObject> formatObject(Object input, Map<String, List<String>> properties)
65 throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported {
66 if (input instanceof Vertex) {
67 logger.debug("Formatting vertex object with properties map filter");
68 return this.getJsonFromVertex((Vertex) input, properties);
69 } else if (input instanceof Tree) {
70 logger.debug("Formatting tree object with properties map filter");
72 return this.getRelatedNodesFromTree((Tree<?>) input, properties);
74 return this.getJsonFromTree((Tree<?>) input);
76 } else if (input instanceof Path) {
77 logger.debug("Formatting path object");
78 return this.getJsonFromPath((Path) input);
80 throw new AAIFormatQueryResultFormatNotSupported();
84 protected abstract Optional<JsonObject> getJsonFromVertex(Vertex input) throws AAIFormatVertexException;
85 protected abstract Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException;
87 protected Optional<JsonObject> getJsonFromPath(Path input) throws AAIFormatVertexException {
88 List<Object> path = input.objects();
90 JsonObject jo = new JsonObject();
91 JsonArray ja = new JsonArray();
93 for (Object o : path) {
94 if (o instanceof Vertex) {
95 Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) o);
96 obj.ifPresent(ja::add);
101 return Optional.of(jo);
105 * Returns an Optional<JsonObject> object using "nodes" as a wrapper to encapsulate json objects
108 * @throws AAIFormatVertexException
110 protected Optional<JsonObject> getJsonFromTree(Tree<?> tree) throws AAIFormatVertexException {
111 if (tree.isEmpty()) {
112 return Optional.of(new JsonObject());
114 String nodeIdentifier = "nodes";
116 JsonObject t = new JsonObject();
117 JsonArray ja = this.getNodesArray(tree, null, nodeIdentifier);
121 logger.debug("Returned empty JsonArray - Could not populate nested json objects for wrapper: {}", nodeIdentifier);
124 return Optional.of(t);
128 * Returns an Optional<JsonObject> object using "related-nodes" to encapsulate nested json objects.
129 * Primarily intended to be utilized by the "as-tree" query parameter feature
133 * @throws AAIFormatVertexException
135 protected Optional<JsonObject> getRelatedNodesFromTree(Tree<?> tree, Map<String, List<String>> properties) throws AAIFormatVertexException {
136 if (tree.isEmpty()) {
137 return Optional.of(new JsonObject());
139 String nodeIdentifier = "related-nodes";
141 // Creating another DS to help with calls in O(1)
142 Map<String, Set<String>> filterPropertiesMap = createFilteredPropertyMap(properties);
144 JsonObject t = new JsonObject();
145 JsonArray ja = this.getNodesArray(tree, filterPropertiesMap, nodeIdentifier);
147 t.add("results", ja);
148 return Optional.of(t);
150 logger.debug("Returned empty JsonArray - Could not populate nested json objects for wrapper: {}", nodeIdentifier);
153 return Optional.empty();
157 * Returns JsonArray Object populated with nested json wrapped by the nodeIdentifier parameter
159 * @param filterPropertiesMap
160 * @param nodeIdentifier
162 * @throws AAIFormatVertexException
164 protected JsonArray getNodesArray(Tree<?> tree, Map<String, Set<String>> filterPropertiesMap, String nodeIdentifier) throws AAIFormatVertexException {
165 JsonArray nodes = new JsonArray();
166 for (Map.Entry<?, ? extends Tree<?>> entry : tree.entrySet()) {
167 JsonObject me = new JsonObject();
168 if (entry.getKey() instanceof Vertex) {
169 Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) entry.getKey());
170 if (obj.isPresent()) {
171 me = getPropertyFilteredObject(obj, filterPropertiesMap);
176 JsonArray ja = this.getNodesArray(entry.getValue(), filterPropertiesMap, nodeIdentifier);
178 me.add(nodeIdentifier, ja);
180 logger.debug("Returned empty JsonArray - Could not populate nested json objects for wrapper: {}", nodeIdentifier);
188 * Returns a Map<String, Set<String>> object through converting given map parameter
192 protected Map<String, Set<String>> createFilteredPropertyMap(Map<String, List<String>> properties) {
193 if (properties == null)
194 return new HashMap<>();
196 Map<String, Set<String>> filterPropertiesMap = new HashMap<>();
197 for (String key : properties.keySet()) {
198 if (!filterPropertiesMap.containsKey(key)) {
199 Set<String> newSet = new HashSet<>();
200 for (String currProperty : properties.get(key)) {
201 currProperty = truncateApostrophes(currProperty);
202 newSet.add(currProperty);
204 filterPropertiesMap.put(key, newSet);
207 return filterPropertiesMap;
211 * Returns a string with it's apostrophes truncated at the start and end.
215 protected String truncateApostrophes(String s) {
216 if (s == null || s.isEmpty()) {
219 if (s.startsWith("'") && s.endsWith("'")) {
220 s = s.substring(1, s.length() - 1);
226 * Filters the given Optional<JsonObject> with the properties under a properties field
227 * or the properties under its respective node type.
229 * @param filterPropertiesMap
232 protected JsonObject getPropertyFilteredObject(Optional<JsonObject> obj, Map<String, Set<String>> filterPropertiesMap) {
233 if (filterPropertiesMap == null || filterPropertiesMap.isEmpty()) {
236 JsonObject jsonObj = obj.get();
237 JsonObject result = new JsonObject();
238 if (jsonObj != null) {
239 String nodeType = "";
240 JsonObject properties = null;
242 for (Map.Entry<String, JsonElement> mapEntry : jsonObj.entrySet()) {
243 String key = mapEntry.getKey(); JsonElement value = mapEntry.getValue();
245 // also, check if payload has node-type and properties fields
246 if (key.equals("node-type") && value != null) {
247 nodeType = value.getAsString();
248 } else if (key.equals("properties") && value != null && value.isJsonObject()) {
249 properties = value.getAsJsonObject();
251 result.add(key, value);
254 // Filter current object based on it containing fields: "node-type" and "properties"
255 if (!nodeType.isEmpty() && properties != null) {
256 filterByNodeTypeAndProperties(result, nodeType, properties, filterPropertiesMap);
258 // filter current object based on the: key - nodeType & value - JsonObject of nodes properties
259 filterByJsonObj(result, jsonObj, filterPropertiesMap);
266 * Returns a JsonObject with filtered properties using "node-type" and "properties"
267 * Used for formats with payloads similar to simple and raw
271 * @param filterPropertiesMap
274 private JsonObject filterByNodeTypeAndProperties(JsonObject result, String nodeType, JsonObject properties, Map<String, Set<String>> filterPropertiesMap) {
275 if (result == null || nodeType == null || nodeType.isEmpty() || properties == null || filterPropertiesMap == null) {
278 if (filterPropertiesMap.containsKey(nodeType)) { // filterPropertiesMap keys are nodeTypes - keys are obtained from the incoming query request
279 Set<String> filterSet = filterPropertiesMap.get(nodeType);
280 JsonObject filteredProperties = new JsonObject();
281 for (String property : filterSet) { // Each nodeType should have a set of properties to be retained in the response
282 if (properties.get(property) != null) {
283 filteredProperties.add(property, properties.get(property));
286 result.remove("properties");
287 result.add("properties", filteredProperties);
293 * Returns a JsonObject with its properties filtered
296 * @param filterPropertiesMap
299 private JsonObject filterByJsonObj(JsonObject result, JsonObject jsonObj, Map<String, Set<String>> filterPropertiesMap) {
300 if (result == null || jsonObj == null || filterPropertiesMap == null) {
304 for (Map.Entry<String, JsonElement> mapEntry : jsonObj.entrySet()) {
305 String key = mapEntry.getKey(); JsonElement value = mapEntry.getValue();
306 JsonObject filteredProperties = new JsonObject();
307 if (value != null && value.isJsonObject() && filterPropertiesMap.containsKey(key)) {
308 JsonObject joProperties = value.getAsJsonObject();
309 Set<String> filterSet = filterPropertiesMap.get(key);
310 for (String property : filterSet) {
311 if (joProperties.get(property) != null) {
312 filteredProperties.add(property, joProperties.get(property));
316 result.add(key, filteredProperties);
323 * Returns a filtered JsonObject with properties contained in the parameter filterPropertiesMap
325 * @param filterPropertiesMap
328 protected JsonObject filterProperties(Optional<JsonObject> properties, String nodeType, Map<String, Set<String>> filterPropertiesMap) {
329 if (filterPropertiesMap == null || filterPropertiesMap.isEmpty()) {
330 return properties.get();
333 JsonObject jo = properties.get();
334 JsonObject result = new JsonObject();
337 for (Map.Entry<String, JsonElement> mapEntry : jo.entrySet()) {
338 String key = mapEntry.getKey();
339 JsonElement value = mapEntry.getValue();
340 result.add(key, value);
344 if (filterPropertiesMap.containsKey(nodeType)) {
345 Set<String> filterSet = filterPropertiesMap.get(nodeType);
346 for (Map.Entry<String, JsonElement> mapEntry : jo.entrySet()) {
347 String key = mapEntry.getKey();
348 if (!filterSet.contains(key)) {
358 public int parallelThreshold() {