TreeFormat - Removed problems triggering Sonar errors
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / serialization / queryformats / TreeFormat.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
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
10  *
11  *    http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.aai.serialization.queryformats;
22
23 import com.att.eelf.configuration.EELFLogger;
24 import com.att.eelf.configuration.EELFManager;
25 import com.google.gson.JsonArray;
26 import com.google.gson.JsonElement;
27 import com.google.gson.JsonObject;
28 import com.google.gson.JsonParser;
29 import java.util.Map.Entry;
30 import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet;
31 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
32 import org.apache.tinkerpop.gremlin.structure.Vertex;
33 import org.onap.aai.db.props.AAIProperties;
34 import org.onap.aai.exceptions.AAIException;
35 import org.onap.aai.introspection.Introspector;
36 import org.onap.aai.introspection.Loader;
37 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
38 import org.onap.aai.logging.LogFormatTools;
39 import org.onap.aai.serialization.db.DBSerializer;
40 import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported;
41 import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
42 import org.onap.aai.serialization.queryformats.params.Depth;
43 import org.onap.aai.serialization.queryformats.params.NodesOnly;
44 import org.onap.aai.serialization.queryformats.utils.UrlBuilder;
45
46 import java.io.UnsupportedEncodingException;
47 import java.util.*;
48
49 public class TreeFormat extends MultiFormatMapper {
50     private static final EELFLogger TREE_FORMAT_LOGGER = EELFManager.getInstance().getLogger(TreeFormat.class);
51     protected JsonParser parser = new JsonParser();
52     protected final DBSerializer serializer;
53     protected final Loader loader;
54     protected final UrlBuilder urlBuilder;
55     protected final int depth;
56     protected final boolean nodesOnly;
57
58     protected TreeFormat(Builder builder) {
59         this.urlBuilder = builder.getUrlBuilder();
60         this.loader = builder.getLoader();
61         this.serializer = builder.getSerializer();
62         this.depth = builder.getDepth();
63         this.nodesOnly = builder.isNodesOnly();
64     }
65
66     @Override
67     public int parallelThreshold() {
68         return 100;
69     }
70
71     public static class Builder implements NodesOnly<Builder>, Depth<Builder> {
72
73         protected final Loader loader;
74         protected final DBSerializer serializer;
75         protected final UrlBuilder urlBuilder;
76         protected boolean includeUrl = false;
77         protected boolean nodesOnly = false;
78         protected int depth = 1;
79         protected boolean modelDriven = false;
80
81         public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) {
82             this.loader = loader;
83             this.serializer = serializer;
84             this.urlBuilder = urlBuilder;
85         }
86
87         protected Loader getLoader() {
88             return this.loader;
89         }
90
91         protected DBSerializer getSerializer() {
92             return this.serializer;
93         }
94
95         protected UrlBuilder getUrlBuilder() {
96             return this.urlBuilder;
97         }
98
99         public Builder includeUrl() {
100             this.includeUrl = true;
101             return this;
102         }
103
104         public Builder nodesOnly(Boolean nodesOnly) {
105             this.nodesOnly = nodesOnly;
106             return this;
107         }
108
109         public boolean isNodesOnly() {
110             return this.nodesOnly;
111         }
112
113         public Builder depth(Integer depth) {
114             this.depth = depth;
115             return this;
116         }
117
118         public int getDepth() {
119             return this.depth;
120         }
121
122         public boolean isIncludeUrl() {
123             return this.includeUrl;
124         }
125
126         public Builder modelDriven() {
127             this.modelDriven = true;
128             return this;
129         }
130
131         public boolean getModelDriven() {
132             return this.modelDriven;
133         }
134
135         public TreeFormat build() {
136             return new TreeFormat(this);
137         }
138     }
139
140     public JsonArray process(List<Object> queryResults, Map<String, List<String>> properties) {
141         JsonArray body = new JsonArray();
142         for (Object o : queryResults) {
143             try {
144                 return this.formatObjectToJsonArray(o, properties).orElseGet( () -> {
145                     TREE_FORMAT_LOGGER.warn("Empty Optional returned by 'formatObjectToJsonArray'");
146                     return body;
147                 });
148             } catch (AAIFormatVertexException e) {
149                 TREE_FORMAT_LOGGER.warn("Failed to format vertex, returning a partial list " + LogFormatTools.getStackTop(e));
150             } catch (AAIFormatQueryResultFormatNotSupported e) {
151                 TREE_FORMAT_LOGGER.warn("Failed to format result type of the query " + LogFormatTools.getStackTop(e));
152             }
153         }
154         return body;
155     }
156
157     public Optional<JsonArray> formatObjectToJsonArray(Object input, Map<String, List<String>> properties)
158         throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported {
159         JsonArray json = new JsonArray();
160         if (input == null)
161             return Optional.of(json);
162         if (input instanceof Tree) {
163             return this.getJsonArrayFromTree((Tree<Object>) input);
164         } else {
165             throw new AAIFormatQueryResultFormatNotSupported();
166         }
167     }
168
169     protected Optional<JsonArray> getJsonArrayFromTree(Tree<Object> tree) throws AAIFormatVertexException {
170         if (tree.isEmpty()) {
171             return Optional.of(new JsonArray());
172         }
173
174         // DSL Query
175         JsonArray jsonArray = new JsonArray();
176         JsonObject jsonObject = new JsonObject();
177         for (Map.Entry<Object, Tree<Object>> entry : tree.entrySet()) {
178             Object o = entry.getKey();
179
180             // DSL Query
181             if (o instanceof BulkSet) {
182                 BulkSet bs = (BulkSet) o;
183                 for (Object o1 : bs) {
184                     Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) o1);
185                     if (obj.isPresent()) {
186                         jsonObject = obj.get();
187                         for (Map.Entry<String, JsonElement> mapEntry : jsonObject.entrySet()) {
188                             JsonElement jsonRootElementContents = mapEntry.getValue();        // getting everyObject inside
189                             if (jsonRootElementContents != null && jsonRootElementContents.isJsonObject()) {
190                                 JsonObject relatedJsonNode = (JsonObject) jsonRootElementContents;
191                                 addRelatedNodesToJsonObject(
192                                     jsonRootElementContents.getAsJsonObject(),
193                                     getRelatedNodes(relatedJsonNode)
194                                 );
195                             }
196                         }
197                         jsonArray.add(jsonObject);
198                     }
199                 }
200             }
201             // Gremlin Query
202             else if (o instanceof Vertex) {
203                 Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) o);
204                 if (obj.isPresent()) {
205                     jsonObject = obj.get();
206                     for (Map.Entry<String, JsonElement> mapEntry : jsonObject.entrySet()) {
207                         JsonElement jsonRootElementContents = mapEntry.getValue();
208                         if (jsonRootElementContents != null && jsonRootElementContents.isJsonObject()) {
209                             addRelatedNodesToJsonObject(
210                                 jsonRootElementContents.getAsJsonObject(),
211                                 getRelatedNodes(entry.getValue()));
212                         }
213                     }
214                     jsonArray.add(jsonObject);
215                 }
216             }
217         }
218         return Optional.of(jsonArray);
219     }
220
221     protected Optional<JsonArray> getRelatedNodes(JsonObject jsonObj) throws AAIFormatVertexException {
222         JsonArray relatedNodes = new JsonArray();
223         for (Map.Entry<String, JsonElement> mapEntry : jsonObj.entrySet()) {
224             String s = mapEntry.getKey();
225             JsonElement jsonRootElementContents = jsonObj.get(s);
226             if (jsonRootElementContents != null && jsonRootElementContents.isJsonObject()) {
227                 JsonObject relatedJsonNode = jsonRootElementContents.getAsJsonObject();
228                 addRelatedNodesToJsonObject(
229                     relatedJsonNode,
230                     this.getRelatedNodes(relatedJsonNode)
231                 );
232                 relatedNodes.add(relatedJsonNode);
233             }
234         }
235         return Optional.of(relatedNodes);
236     }
237
238     protected Optional<JsonArray> getRelatedNodes(Tree<Object> tree) throws AAIFormatVertexException {
239         JsonArray relatedNodes = new JsonArray();
240         for (Map.Entry<Object, Tree<Object>> entry : tree.entrySet()) {
241             Object o = entry.getKey();
242
243             if (o instanceof Vertex) {
244                 processVertex(relatedNodes, entry, (Vertex) o);
245             }
246         }
247         return Optional.of(relatedNodes);
248     }
249
250     private void processVertex(JsonArray relatedNodes, Entry<Object, Tree<Object>> entry, Vertex o)
251         throws AAIFormatVertexException {
252         Optional<JsonObject> obj = this.getJsonFromVertex(o);
253         if (obj.isPresent()) {
254             JsonObject jsonObj = obj.get();
255             for (Entry<String, JsonElement> mapEntry : jsonObj.entrySet()) {
256                 JsonElement jsonRootElementContents = mapEntry.getValue();
257                 if (jsonRootElementContents != null && jsonRootElementContents.isJsonObject()) {
258                     JsonObject jsonObject = addRelatedNodesToJsonObject(
259                         jsonRootElementContents.getAsJsonObject(),
260                         getRelatedNodes(entry.getValue()));
261                     relatedNodes.add(jsonObject);
262                 }
263             }
264         }
265     }
266
267
268     private static JsonObject addRelatedNodesToJsonObject(JsonObject jsonObject, Optional<JsonArray> relatedNodesOpt) {
269         relatedNodesOpt.ifPresent( relatedNodes -> {
270             if (relatedNodes.size() > 0) {
271                 jsonObject.add("related-nodes", relatedNodes);
272             }
273         });
274
275         return jsonObject;
276     }
277
278     /**
279      *
280      * Returns an Optional<JsonObject> to convert the contents from the given Vertex object into a JsonObject.
281      * The fields returned are to record the time stamp of the creation/modification of the object, the user responsible
282      * for
283      * the change, and the last http method performed on the object.
284      *
285      * @param v
286      * @return
287      * @throws AAIFormatVertexException
288      */
289     @Override
290     protected Optional<JsonObject> getJsonFromVertex(Vertex v) throws AAIFormatVertexException {
291
292         JsonObject json = new JsonObject();
293
294         Optional<JsonObject> jsonObject = this.vertexToJsonObject(v);
295         if (jsonObject.isPresent()) {
296             json.add(v.<String>property(AAIProperties.NODE_TYPE).orElse(null), jsonObject.get());
297         } else {
298             return Optional.empty();
299         }
300         return Optional.of(json);
301     }
302
303     protected Optional<JsonObject> vertexToJsonObject(Vertex v) throws AAIFormatVertexException {
304         try {
305             final Introspector obj =
306                 getLoader().introspectorFromName(v.<String>property(AAIProperties.NODE_TYPE).orElse(null));
307
308             final List<Vertex> wrapper = new ArrayList<>();
309
310             wrapper.add(v);
311
312             try {
313                 getSerializer().dbToObject(wrapper, obj, this.depth, this.nodesOnly, "false");
314             } catch (AAIException | UnsupportedEncodingException e) {
315                 throw new AAIFormatVertexException(
316                     "Failed to format vertex - error while serializing: " + e.getMessage(), e);
317             }
318
319             final String json = obj.marshal(false);
320
321             return Optional.of(getParser().parse(json).getAsJsonObject());
322         } catch (AAIUnknownObjectException e) {
323             return Optional.empty();
324         }
325     }
326
327     private Loader getLoader() {
328         return loader;
329     }
330
331     private DBSerializer getSerializer() {
332         return serializer;
333     }
334
335     private JsonParser getParser() {
336         return parser;
337     }
338
339
340     @Override
341     protected Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException {
342         return Optional.empty();
343     }
344 }