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