[AAI] Fix doc config files
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / serialization / queryformats / Resource.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.JsonArray;
24 import com.google.gson.JsonElement;
25 import com.google.gson.JsonObject;
26 import com.google.gson.JsonParser;
27 import java.io.UnsupportedEncodingException;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Optional;
32 import java.util.Set;
33 import javax.ws.rs.core.MultivaluedMap;
34 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
35 import org.apache.tinkerpop.gremlin.structure.Vertex;
36 import org.onap.aai.db.props.AAIProperties;
37 import org.onap.aai.exceptions.AAIException;
38 import org.onap.aai.introspection.Introspector;
39 import org.onap.aai.introspection.Loader;
40 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
41 import org.onap.aai.serialization.db.DBSerializer;
42 import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
43 import org.onap.aai.serialization.queryformats.params.AsTree;
44 import org.onap.aai.serialization.queryformats.params.Depth;
45 import org.onap.aai.serialization.queryformats.params.NodesOnly;
46 import org.onap.aai.serialization.queryformats.utils.UrlBuilder;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 public class Resource extends MultiFormatMapper {
51
52     private static final Logger logger = LoggerFactory.getLogger(Resource.class);
53
54     private final Loader loader;
55     private final DBSerializer serializer;
56     private final JsonParser parser;
57     private final UrlBuilder urlBuilder;
58     private final boolean includeUrl;
59     private final boolean nodesOnly;
60     private final int depth;
61     private final boolean isSkipRelatedTo;
62
63     public Resource(Builder builder) {
64         this.parser = new JsonParser();
65         this.loader = builder.getLoader();
66         this.serializer = builder.getSerializer();
67         this.urlBuilder = builder.getUrlBuilder();
68         this.includeUrl = builder.isIncludeUrl();
69         this.nodesOnly = builder.isNodesOnly();
70         this.depth = builder.getDepth();
71         this.isSkipRelatedTo = builder.isSkipRelatedTo();
72         this.isTree = builder.isTree();
73     }
74
75     @Override
76     protected Optional<JsonObject> getRelatedNodesFromTree(Tree<?> tree, Map<String, List<String>> properties) throws AAIFormatVertexException {
77         if (tree.isEmpty()) {
78             return Optional.of(new JsonObject());
79         }
80
81         Map<String, Set<String>> filterPropertiesMap = createFilteredPropertyMap(properties);
82
83         JsonObject t = new JsonObject();
84         JsonArray ja = this.getRelatedNodesArray(tree, filterPropertiesMap,"related-nodes");
85         if (ja.size() > 0) {
86             t.add("results", ja);
87             return Optional.of(t);
88         }
89
90         return Optional.empty();
91     }
92
93     protected JsonArray getRelatedNodesArray(Tree<?> tree, Map<String, Set<String>> filterPropertiesMap, String nodeIdentifier) throws AAIFormatVertexException {
94         JsonArray nodes = new JsonArray();
95         if (tree.isEmpty()) {
96             return nodes;
97         }
98         for (Map.Entry<?, ? extends Tree<?>> entry : tree.entrySet()) {
99             JsonObject me = new JsonObject();
100             if (entry.getKey() instanceof Vertex) {
101                 Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) entry.getKey());
102                 if (obj.isPresent()) {
103                     me = getPropertyFilteredObject(obj, filterPropertiesMap);
104                 } else {
105                     continue;
106                 }
107             }
108             JsonArray ja = this.getRelatedNodesArray(entry.getValue(), filterPropertiesMap, nodeIdentifier);
109             if (ja.size() > 0) {
110                 try {
111                     for (Map.Entry<String, JsonElement> mapEntry : me.entrySet()) {
112                         JsonElement value = mapEntry.getValue();
113                         if (value != null && value.isJsonObject()) {
114                             value.getAsJsonObject().add(nodeIdentifier, ja);
115                         }
116                     }
117                 } catch(Exception e) {
118                     logger.debug("Failed to add related-nodes array: {}", e.getMessage());
119                     throw new AAIFormatVertexException("Failed to add related-nodes array: " + e.getMessage(), e);
120                 }
121             }
122             nodes.add(me);
123         }
124         return nodes;
125     }
126
127     @Override
128     protected Optional<JsonObject> getJsonFromVertex(Vertex v) throws AAIFormatVertexException {
129
130         JsonObject json = new JsonObject();
131
132         if (this.includeUrl) {
133             json.addProperty("url", this.urlBuilder.pathed(v));
134         }
135         Optional<JsonObject> jsonObject = this.vertexToJsonObject(v);
136         if (jsonObject.isPresent()) {
137             json.add(v.<String>property(AAIProperties.NODE_TYPE).orElse(null), jsonObject.get());
138         } else {
139             return Optional.empty();
140         }
141         return Optional.of(json);
142     }
143
144     @Override
145     protected Optional<JsonObject> getJsonFromVertex(Vertex v, Map<String, List<String>> properties) throws AAIFormatVertexException {
146         JsonObject json = new JsonObject();
147
148         if (this.includeUrl) {
149             json.addProperty("url", this.urlBuilder.pathed(v));
150         }
151         Optional<JsonObject> jsonObject = this.vertexToJsonObject(v);
152         if (jsonObject.isPresent()) {
153             String nodeType = v.<String>value(AAIProperties.NODE_TYPE);
154             Map<String, Set<String>> filterPropertiesMap = createFilteredPropertyMap(properties);       // this change is for resource_and_url with/out as-tree. and no as-tree req
155             JsonObject jo = filterProperties(jsonObject, nodeType, filterPropertiesMap);
156             json.add(v.<String>property(AAIProperties.NODE_TYPE).orElse(null), jo);
157         } else {
158             return Optional.empty();
159         }
160         return Optional.of(json);
161     }
162
163     protected Optional<JsonObject> vertexToJsonObject(Vertex v) throws AAIFormatVertexException {
164         if (v == null) {
165             return Optional.empty();
166         }
167         try {
168             final Introspector obj =
169                 getLoader().introspectorFromName(v.<String>property(AAIProperties.NODE_TYPE).orElse(null));
170
171             final List<Vertex> wrapper = new ArrayList<>();
172
173             wrapper.add(v);
174
175             try {
176                 getSerializer().dbToObject(wrapper, obj, this.depth, this.nodesOnly, "false", isSkipRelatedTo);
177             } catch (AAIException | UnsupportedEncodingException e) {
178                 throw new AAIFormatVertexException(
179                     "Failed to format vertex - error while serializing: " + e.getMessage(), e);
180             }
181
182             final String json = obj.marshal(false);
183
184             return Optional.of(getParser().parse(json).getAsJsonObject());
185         } catch (AAIUnknownObjectException e) {
186             return Optional.empty();
187         }
188     }
189
190     @Override
191     public int parallelThreshold() {
192         return 20;
193     }
194
195     private Loader getLoader() {
196         return loader;
197     }
198
199     private DBSerializer getSerializer() {
200         return serializer;
201     }
202
203     private JsonParser getParser() {
204         return parser;
205     }
206
207     public static class Builder implements NodesOnly<Builder>, Depth<Builder>, AsTree<Builder> {
208
209         private final Loader loader;
210         private final DBSerializer serializer;
211         private final UrlBuilder urlBuilder;
212         private boolean includeUrl = false;
213         private boolean nodesOnly = false;
214         private int depth = 1;
215         private MultivaluedMap<String, String> params;
216         private boolean tree = false;
217
218         public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) {
219             this.loader = loader;
220             this.serializer = serializer;
221             this.urlBuilder = urlBuilder;
222         }
223
224         public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder, MultivaluedMap<String, String> params) {
225             this.loader = loader;
226             this.serializer = serializer;
227             this.urlBuilder = urlBuilder;
228             this.params = params;
229         }
230
231         protected Loader getLoader() {
232             return this.loader;
233         }
234
235         protected DBSerializer getSerializer() {
236             return this.serializer;
237         }
238
239         protected UrlBuilder getUrlBuilder() {
240             return this.urlBuilder;
241         }
242
243         protected MultivaluedMap<String, String> getParams() { return this.params; }
244
245         public boolean isSkipRelatedTo() {
246             if (params != null) {
247                 boolean isSkipRelatedTo = true;
248                 if (params.containsKey("skip-related-to")) {
249                     String skipRelatedTo = params.getFirst("skip-related-to");
250                     isSkipRelatedTo = !(skipRelatedTo != null && skipRelatedTo.equals("false"));
251                 } else {
252                     // if skip-related-to param is missing, then default it to false;
253                     isSkipRelatedTo = false;
254                 }
255                 return isSkipRelatedTo;
256             }
257             return true;
258         }
259
260         protected boolean isTree() { return this.tree; }
261
262         public Builder isTree(Boolean tree) {
263             this.tree = tree;
264             return this;
265         }
266
267
268         public Builder includeUrl() {
269             this.includeUrl = true;
270             return this;
271         }
272
273         public Builder nodesOnly(Boolean nodesOnly) {
274             this.nodesOnly = nodesOnly;
275             return this;
276         }
277
278         public boolean isNodesOnly() {
279             return this.nodesOnly;
280         }
281
282         public Builder depth(Integer depth) {
283             this.depth = depth;
284             return this;
285         }
286
287         public int getDepth() {
288             return this.depth;
289         }
290
291         public boolean isIncludeUrl() {
292             return this.includeUrl;
293         }
294
295         public Resource build() {
296             return new Resource(this);
297         }
298     }
299 }