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