Fix Fortify scan violation
[aai/gizmo.git] / src / main / java / org / onap / schema / RelationshipSchemaValidator.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 Amdocs
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21 package org.onap.schema;
22
23 import com.google.gson.JsonElement;
24 import com.google.gson.JsonNull;
25
26 import org.onap.crud.entity.Edge;
27 import org.onap.crud.entity.Vertex;
28 import org.onap.crud.exception.CrudException;
29 import org.onap.crud.service.EdgePayload;
30 import org.onap.crud.util.CrudServiceUtil;
31 import org.onap.schema.OxmModelValidator.Metadata;
32 import org.radeox.util.logging.Logger;
33
34 import java.util.HashMap;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
39 import javax.ws.rs.core.Response.Status;
40
41 public class RelationshipSchemaValidator {
42
43   public static final String SOURCE_NODE = "source";
44   public static final String TARGET_NODE = "target";
45
46   final static Pattern urlPattern = Pattern.compile("services/inventory/(.*)/(.*)/(.*)");
47
48   public static Map<String, Object> resolveCollectionfilter(String version, String type,
49                                                             Map<String, String> filter)
50       throws CrudException {
51
52     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
53     if (schema == null) {
54       throw new CrudException("", Status.NOT_FOUND);
55     }
56
57     Map<String, Class<?>> props = schema.lookupRelationType(type);
58     Map<String, Object> result = new HashMap<String, Object>();
59
60     for (String key : filter.keySet()) {
61
62       if (props.containsKey(key)) {
63         try {
64           Object value = CrudServiceUtil.validateFieldType(filter.get(key), props.get(key));
65           result.put(key, value);
66         } catch (Exception ex) {
67           // Skip any exceptions thrown while validating the filter
68           // key value
69           continue;
70         }
71       }
72     }
73
74     return result;
75
76   }
77
78   public static void validateType(String version, String type) throws CrudException {
79
80     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
81     if (!schema.isValidType(type)) {
82       throw new CrudException("Invalid " + RelationshipSchema.SCHEMA_RELATIONSHIP_TYPE
83           + ": " + type,
84           Status.BAD_REQUEST);
85     }
86
87   }
88
89   public static Edge validateIncomingAddPayload(String version, String type, Vertex sourceNode,
90                                                 Vertex targetNode, JsonElement properties)
91       throws CrudException {
92     EdgePayload payload = new EdgePayload();
93     payload.setSource("services/inventory/" + version + "/" + sourceNode.getType()
94         + "/" + sourceNode.getId().get());
95     payload.setTarget("services/inventory/" + version + "/" + targetNode.getType()
96         + "/" + targetNode.getId().get());
97     payload.setType(type);
98     payload.setProperties(properties);
99     return validateIncomingAddPayload(version, type, payload);
100   }
101
102   public static Edge validateIncomingAddPayload(String version, String type, EdgePayload payload)
103       throws CrudException {
104     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
105
106     try {
107
108       if (payload.getSource() == null || payload.getTarget() == null) {
109         throw new CrudException("Source/Target not specified", Status.BAD_REQUEST);
110       }
111
112       Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
113       Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
114
115       if (!sourceMatcher.matches() || !targetMatcher.matches()) {
116         throw new CrudException("Invalid Source/Target Urls", Status.BAD_REQUEST);
117       }
118
119       // create key based on source:target:relationshipType
120       String sourceNodeType = sourceMatcher.group(2);
121       String targetNodeType = targetMatcher.group(2);
122
123       String sourceNodeId = sourceMatcher.group(3);
124       String targetNodeId = targetMatcher.group(3);
125
126       String key = sourceNodeType + ":" + targetNodeType + ":" + type;
127
128       // find the validate the key from the schema
129       Map<String, Class<?>> schemaObject = schema.lookupRelation(key);
130
131       if (schemaObject == null) {
132         throw new CrudException("Invalid source/target/relationship type: " + key,
133             Status.BAD_REQUEST);
134       }
135
136       Edge.Builder modelEdgeBuilder = new Edge.Builder(type);
137
138       modelEdgeBuilder.source(new Vertex.Builder(sourceNodeType).id(sourceNodeId).build());
139       modelEdgeBuilder.target(new Vertex.Builder(targetNodeType).id(targetNodeId).build());
140
141       // validate it properties
142       validateEdgeProps(modelEdgeBuilder, payload.getProperties(), schemaObject);
143
144       return modelEdgeBuilder.build();
145     } catch (Exception ex) {
146
147       throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
148     }
149
150   }
151
152   public static Edge validateIncomingPatchPayload(Edge edge, String version, EdgePayload payload)
153       throws CrudException {
154     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
155
156     try {
157       if (payload.getSource() != null) {
158         Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
159
160         if (!sourceMatcher.matches()) {
161           throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
162         }
163         String sourceNodeId = sourceMatcher.group(3);
164         if (!sourceNodeId.equals(edge.getSource().getId().get())) {
165           throw new CrudException("Source can't be updated", Status.BAD_REQUEST);
166         }
167       }
168
169       if (payload.getTarget() != null) {
170         Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
171
172         if (!targetMatcher.matches()) {
173           throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
174         }
175         String sourceNodeId = targetMatcher.group(3);
176         if (!sourceNodeId.equals(edge.getTarget().getId().get())) {
177           throw new CrudException("Target can't be updated", Status.BAD_REQUEST);
178         }
179       }
180       
181       // Remove the timestamp properties from the existing edge, as these should be managed by Champ.
182       Map<String,Object> existingProps = edge.getProperties();
183       
184       if (existingProps.containsKey(Metadata.CREATED_TS.propertyName())) {
185         existingProps.remove(Metadata.CREATED_TS.propertyName());
186       }
187       if (existingProps.containsKey(Metadata.UPDATED_TS.propertyName())) {
188         existingProps.remove(Metadata.UPDATED_TS.propertyName());
189       }
190       
191       // create key based on source:target:relationshipType
192
193       String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
194           + ":" + edge.getType();
195
196       // find the validate the key from the schema
197       Map<String, Class<?>> schemaObject = schema.lookupRelation(key);
198
199       if (schemaObject == null) {
200         Logger.warn("key :" + key
201             + " not found in relationship schema . Skipping the schema validation");
202         return edge;
203       }
204
205       Set<Map.Entry<String, JsonElement>> entries = payload.getProperties()
206           .getAsJsonObject().entrySet();
207
208       for (Map.Entry<String, JsonElement> entry : entries) {
209
210         if (!schemaObject.containsKey(entry.getKey())) {
211           throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST);
212         } else if (entry.getValue() instanceof JsonNull && edge.getProperties()
213             .containsKey(entry.getKey())) {
214           edge.getProperties().remove(entry.getKey());
215         } else if (!(entry.getValue() instanceof JsonNull)) {
216           Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(),
217               schemaObject.get(entry.getKey()));
218           edge.getProperties().put(entry.getKey(), value);
219         }
220
221       }
222
223       return edge;
224
225     } catch (Exception ex) {
226
227       throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
228     }
229   }
230
231   public static Edge validateIncomingUpdatePayload(Edge edge, String version, Vertex sourceNode,
232                                                    Vertex targetNode, JsonElement properties)
233       throws CrudException {
234     EdgePayload payload = new EdgePayload();
235     payload.setSource("services/inventory/" + version + "/" + sourceNode.getType()
236         + "/" + sourceNode.getId().get());
237     payload.setTarget("services/inventory/" + version + "/" + targetNode.getType()
238         + "/" + targetNode.getId().get());
239     payload.setType(edge.getType());
240     payload.setProperties(properties);
241     return validateIncomingUpdatePayload(edge, version, payload);
242   }
243
244   public static Edge validateIncomingUpdatePayload(Edge edge, String version, EdgePayload payload)
245       throws CrudException {
246     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
247
248     try {
249
250       if (payload.getSource() != null) {
251         Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
252
253         if (!sourceMatcher.matches()) {
254           throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
255         }
256         String sourceNodeId = sourceMatcher.group(3);
257         if (!sourceNodeId.equals(edge.getSource().getId().get())) {
258           throw new CrudException("Source can't be updated", Status.BAD_REQUEST);
259         }
260       }
261
262       if (payload.getTarget() != null) {
263         Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
264
265         if (!targetMatcher.matches()) {
266           throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
267         }
268         String sourceNodeId = targetMatcher.group(3);
269         if (!sourceNodeId.equals(edge.getTarget().getId().get())) {
270           throw new CrudException("Target can't be updated", Status.BAD_REQUEST);
271         }
272       }
273       // create key based on source:target:relationshipType
274
275       String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
276           + ":" + edge.getType();
277
278       // find the validate the key from the schema
279       Map<String, Class<?>> schemaObject = schema.lookupRelation(key);
280
281       if (schemaObject == null) {
282         Logger.warn("key :" + key
283             + " not found in relationship schema . Skipping the schema validation");
284         return edge;
285       }
286
287       Edge.Builder updatedEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId().get());
288
289       updatedEdgeBuilder
290           .source(new Vertex.Builder(edge.getSource().getType()).id(edge.getSource().getId()
291               .get()).build());
292       updatedEdgeBuilder
293           .target(new Vertex.Builder(edge.getTarget().getType()).id(edge.getTarget().getId()
294               .get()).build());
295
296       validateEdgeProps(updatedEdgeBuilder, payload.getProperties(), schemaObject);
297
298       return updatedEdgeBuilder.build();
299     } catch (Exception ex) {
300
301       throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
302     }
303   }
304
305
306   private static void validateEdgeProps(Edge.Builder builder, JsonElement props,
307                                         Map<String, Class<?>> schemaObject)
308       throws CrudException {
309     Set<Map.Entry<String, JsonElement>> entries = props.getAsJsonObject().entrySet();
310
311     for (Map.Entry<String, JsonElement> entry : entries) {
312
313       if (!schemaObject.containsKey(entry.getKey())) {
314         throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST);
315       } else {
316         Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(),
317             schemaObject.get(entry.getKey()));
318         builder.property(entry.getKey(), value);
319       }
320
321     }
322
323   }
324
325   public static Edge validateOutgoingPayload(String version, Edge edge) throws CrudException {
326
327     Edge.Builder modelEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId()
328         .get()).source(edge.getSource())
329         .target(edge.getTarget());
330
331     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
332
333     String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
334         + ":" + edge.getType();
335     Map<String, Class<?>> schemaObject = schema.lookupRelation(key);
336
337     if (schemaObject == null || schemaObject.isEmpty()) {
338       return edge;
339     }
340
341     for (String prop : edge.getProperties().keySet()) {
342       if (schemaObject.containsKey(prop)) {
343         modelEdgeBuilder.property(prop, edge.getProperties().get(prop));
344       }
345
346     }
347     return modelEdgeBuilder.build();
348   }
349
350     
351   public static String vertexTypeFromUri(String uri) throws CrudException {
352       
353     Matcher matcher = urlPattern.matcher(uri);
354
355     if (!matcher.matches()) {
356       throw new CrudException("Invalid Source/Target Urls", Status.BAD_REQUEST);
357     }
358
359     return matcher.group(2);
360   }
361 }