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