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