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