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 / Aggregate.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.google.gson.Gson;
24 import com.google.gson.JsonArray;
25 import com.google.gson.JsonObject;
26 import com.google.gson.JsonParser;
27
28 import java.io.UnsupportedEncodingException;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Optional;
35 import java.util.Set;
36 import java.util.stream.Collectors;
37 import java.util.stream.Stream;
38
39 import org.apache.tinkerpop.gremlin.structure.Vertex;
40 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
41 import org.onap.aai.db.props.AAIProperties;
42 import org.onap.aai.exceptions.AAIException;
43 import org.onap.aai.introspection.Introspector;
44 import org.onap.aai.introspection.Loader;
45 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
46 import org.onap.aai.logging.LogFormatTools;
47 import org.onap.aai.serialization.db.DBSerializer;
48 import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported;
49 import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
50 import org.onap.aai.serialization.queryformats.params.AsTree;
51 import org.onap.aai.serialization.queryformats.params.Depth;
52 import org.onap.aai.serialization.queryformats.params.NodesOnly;
53 import org.onap.aai.serialization.queryformats.utils.UrlBuilder;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 public class Aggregate extends MultiFormatMapper {
58     private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleFormat.class);
59     protected JsonParser parser = new JsonParser();
60     protected final DBSerializer serializer;
61     protected final Loader loader;
62     protected final UrlBuilder urlBuilder;
63     protected final int depth;
64     protected final boolean nodesOnly;
65
66     protected Aggregate(Builder builder) {
67         this.urlBuilder = builder.getUrlBuilder();
68         this.loader = builder.getLoader();
69         this.serializer = builder.getSerializer();
70         this.depth = builder.getDepth();
71         this.nodesOnly = builder.isNodesOnly();
72         this.isTree = builder.isTree();
73     }
74
75     @Override
76     public Optional<JsonObject> getJsonFromVertex(Vertex v, Map<String, List<String>> selectedProps)
77             throws AAIFormatVertexException {
78         JsonObject json = new JsonObject();
79         JsonObject outer = new JsonObject();
80         Optional<JsonObject> properties = this.createSelectedPropertiesObject(v, selectedProps);
81         if (properties.isPresent()) {
82             json.add("properties", properties.get());
83             outer.add(this.urlBuilder.pathed(v), json.getAsJsonObject());
84         } else {
85             return Optional.empty();
86         }
87         return Optional.of(outer);
88     }
89
90     @Override
91     public int parallelThreshold() {
92         return 100;
93     }
94
95     public Optional<JsonObject> createPropertiesObject(Vertex v) throws AAIFormatVertexException {
96         try {
97             final Introspector obj =
98                     loader.introspectorFromName(v.<String>property(AAIProperties.NODE_TYPE).orElse(null));
99
100             final List<Vertex> wrapper = new ArrayList<>();
101             wrapper.add(v);
102
103             try {
104                 serializer.dbToObject(wrapper, obj, 0, true, "false");
105             } catch (AAIException | UnsupportedEncodingException e) {
106                 throw new AAIFormatVertexException(
107                         "Failed to format vertex - error while serializing: " + e.getMessage(), e);
108             }
109
110             final String json = obj.marshal(false);
111             return Optional.of(parser.parse(json).getAsJsonObject());
112         } catch (AAIUnknownObjectException e) {
113             return Optional.empty();
114         }
115     }
116
117     public Optional<JsonObject> createSelectedPropertiesObject(Vertex v, Map<String, List<String>> selectedProps)
118             throws AAIFormatVertexException {
119         JsonObject json = new JsonObject();
120         Set<String> propList = null;
121         String nodeType = v.<String>value(AAIProperties.NODE_TYPE);
122         if (selectedProps != null && !selectedProps.isEmpty() && selectedProps.containsKey(nodeType)) {
123             propList = removeSingleQuotesForProperties(selectedProps.get(nodeType));
124         }
125         Iterator<VertexProperty<Object>> iter = v.properties();
126
127         Gson gson = new Gson();
128         while (iter.hasNext()) {
129             VertexProperty<Object> prop = iter.next();
130             if (propList != null && !propList.isEmpty()) {
131                 if (propList.contains(prop.label())) {
132                     if (prop.value() instanceof String) {
133                         json.addProperty(prop.key(), (String) prop.value());
134                     } else if (prop.value() instanceof Boolean) {
135                         json.addProperty(prop.key(), (Boolean) prop.value());
136                     } else if (prop.value() instanceof Number) {
137                         json.addProperty(prop.key(), (Number) prop.value());
138                     } else if (prop.value() instanceof List) {
139                         json.addProperty(prop.key(), gson.toJson(prop.value()));
140                     } else {
141                         // throw exception?
142                         return Optional.empty();
143                     }
144                 }
145             } else {
146                 return this.createPropertiesObject(v);
147             }
148         }
149
150         return Optional.of(json);
151     }
152
153     private Set<String> removeSingleQuotesForProperties(List<String> props) {
154         if (props != null && !props.isEmpty()) {
155             return props.stream().map(e -> e.substring(1, e.length() - 1)).collect(Collectors.toSet());
156         } else {
157             return Collections.emptySet();
158         }
159     }
160
161     public JsonArray process(List<Object> queryResults, Map<String, List<String>> properties) {
162         JsonArray body = new JsonArray();
163         Stream<Object> stream;
164         if (queryResults.size() >= this.parallelThreshold()) {
165             stream = queryResults.parallelStream();
166         } else {
167             stream = queryResults.stream();
168         }
169         final boolean isParallel = stream.isParallel();
170
171         stream.map(o -> {
172             try {
173                 return this.formatObject(o, properties);
174             } catch (AAIFormatVertexException e) {
175                 LOGGER.warn("Failed to format vertex, returning a partial list " + LogFormatTools.getStackTop(e));
176             } catch (AAIFormatQueryResultFormatNotSupported e) {
177                 LOGGER.warn("Failed to format result type of the query " + LogFormatTools.getStackTop(e));
178             }
179
180             return Optional.<JsonObject>empty();
181         }).filter(Optional::isPresent).map(Optional::get).forEach(json -> {
182             if (isParallel) {
183                 synchronized (body) {
184                     body.add(json);
185                 }
186             } else {
187                 body.add(json);
188             }
189         });
190         return body;
191     }
192
193     @Override
194     public Optional<JsonObject> formatObject(Object input, Map<String, List<String>> properties)
195             throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported {
196         JsonObject json = new JsonObject();
197         if (input instanceof ArrayList) {
198             Optional<JsonArray> ja = processInput(input, properties);
199             json.add("results", ja.get());
200         } else {
201             throw new AAIFormatQueryResultFormatNotSupported();
202         }
203         return Optional.of(json);
204     }
205
206     private Optional<JsonArray> processInput(Object input, Map<String, List<String>> properties)
207             throws AAIFormatVertexException {
208         JsonArray json = new JsonArray();
209         for (Object l : (ArrayList) input) {
210             if (l instanceof ArrayList) {
211                 JsonArray inner = new JsonArray();
212                 for (Vertex o : (ArrayList<Vertex>) l) {
213                     if (o instanceof Vertex) {
214                         Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) o, properties);
215                         if (obj.isPresent()) {
216                             inner.add(obj.get());
217                         } else {
218                             continue;
219                         }
220                     }
221                 }
222                 json.add(inner);
223             } else {
224                 Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) l, properties);
225                 if (obj.isPresent())
226                     json.add(obj.get());
227             }
228         }
229         return Optional.of(json);
230     }
231
232     public static class Builder implements NodesOnly<Builder>, Depth<Builder>, AsTree<Builder> {
233
234         protected final Loader loader;
235         protected final DBSerializer serializer;
236         protected final UrlBuilder urlBuilder;
237         protected boolean includeUrl = false;
238         protected boolean nodesOnly = false;
239         protected int depth = 1;
240         protected boolean modelDriven = false;
241         private boolean tree = false;
242
243         public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) {
244             this.loader = loader;
245             this.serializer = serializer;
246             this.urlBuilder = urlBuilder;
247         }
248
249         protected boolean isTree() {
250             return this.tree;
251         }
252
253         public Builder isTree(Boolean tree) {
254             this.tree = tree;
255             return this;
256         }
257
258         protected Loader getLoader() {
259             return this.loader;
260         }
261
262         protected DBSerializer getSerializer() {
263             return this.serializer;
264         }
265
266         protected UrlBuilder getUrlBuilder() {
267             return this.urlBuilder;
268         }
269
270         public Builder includeUrl() {
271             this.includeUrl = true;
272             return this;
273         }
274
275         public Builder nodesOnly(Boolean nodesOnly) {
276             this.nodesOnly = nodesOnly;
277             return this;
278         }
279
280         public boolean isNodesOnly() {
281             return this.nodesOnly;
282         }
283
284         public Builder depth(Integer depth) {
285             this.depth = depth;
286             return this;
287         }
288
289         public int getDepth() {
290             return this.depth;
291         }
292
293         public boolean isIncludeUrl() {
294             return this.includeUrl;
295         }
296
297         public Builder modelDriven() {
298             this.modelDriven = true;
299             return this;
300         }
301
302         public boolean getModelDriven() {
303             return this.modelDriven;
304         }
305
306         public Aggregate build() {
307             return new Aggregate(this);
308         }
309     }
310
311     @Override
312     protected Optional<JsonObject> getJsonFromVertex(Vertex v) throws AAIFormatVertexException {
313
314         JsonObject json = new JsonObject();
315         json.addProperty("url", this.urlBuilder.pathed(v));
316         Optional<JsonObject> properties = this.createPropertiesObject(v);
317         if (properties.isPresent()) {
318             json.add("properties", properties.get());
319         } else {
320             return Optional.empty();
321         }
322         return Optional.of(json);
323     }
324 }