Remove Multiplicity feature
[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 java.util.HashMap;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29 import javax.ws.rs.core.Response.Status;
30
31 import org.onap.crud.entity.Edge;
32 import org.onap.crud.entity.Vertex;
33 import org.onap.crud.exception.CrudException;
34 import org.onap.crud.service.EdgePayload;
35 import org.onap.crud.util.CrudServiceUtil;
36 import org.onap.schema.OxmModelValidator.Metadata;
37 import org.radeox.util.logging.Logger;
38
39 import com.google.gson.JsonElement;
40 import com.google.gson.JsonNull;
41
42 public class RelationshipSchemaValidator {
43
44         public static final String SOURCE_NODE = "source";
45         public static final String TARGET_NODE = "target";
46         
47         final static Pattern urlPattern = Pattern.compile("services/inventory/(.*)/(.*)/(.*)");
48         
49         public static Map<String, Object> resolveCollectionfilter(String version, String type,Map<String, String> filter)  throws CrudException {
50     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
51     if (schema == null) {
52       throw new CrudException("", Status.NOT_FOUND);
53     }
54
55     Map<String, Class<?>> props = schema.lookupRelationType(type);
56     Map<String, Object> result = new HashMap<String, Object>();
57
58     for (String key : filter.keySet()) {
59
60       if (props.containsKey(key)) {
61         try {
62           Object value = CrudServiceUtil.validateFieldType(filter.get(key), props.get(key));
63           result.put(key, value);
64         } catch (Exception ex) {
65           // Skip any exceptions thrown while validating the filter key value
66           continue;
67         }
68       }
69     }
70     return result;
71   }
72
73   public static void validateType(String version, String type) throws CrudException {
74     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
75     if (!schema.isValidType(type)) {
76       throw new CrudException("Invalid " + RelationshipSchema.SCHEMA_RELATIONSHIP_TYPE
77           + ": " + type,
78           Status.BAD_REQUEST);
79     }
80
81   }
82
83   public static Edge validateIncomingAddPayload(String version, String type, Vertex sourceNode, Vertex targetNode, JsonElement properties) throws CrudException {
84         EdgePayload payload = new EdgePayload();
85         payload.setSource("services/inventory/" + version + "/" + sourceNode.getType() + "/" + sourceNode.getId().get());
86         payload.setTarget("services/inventory/" + version + "/" + targetNode.getType() + "/" + targetNode.getId().get());
87         payload.setType(type);
88         payload.setProperties(properties);
89         
90         return validateIncomingAddPayload(version, type, payload);
91   }
92
93   public static Edge validateIncomingAddPayload(String version, String type, EdgePayload payload)
94       throws CrudException {
95     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
96
97     try {
98       if (payload.getSource() == null || payload.getTarget() == null) {
99         throw new CrudException("Source/Target not specified", Status.BAD_REQUEST);
100       }
101
102       Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
103       Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
104       
105       if (!sourceMatcher.matches() || !targetMatcher.matches()) {
106           throw new CrudException("Invalid Source/Target Urls", Status.BAD_REQUEST);
107       }
108       
109       // create key based on source:target:relationshipType
110       String sourceNodeType = sourceMatcher.group(2);
111       String targetNodeType = targetMatcher.group(2);
112       
113       String sourceNodeId = sourceMatcher.group(3);
114       String targetNodeId = targetMatcher.group(3);
115       
116       String key = sourceNodeType + ":" + targetNodeType + ":" + type;
117
118       // find the validate the key from the schema
119       Map<String, Class<?>> schemaObject = schema.lookupRelation(key);
120
121       if (schemaObject == null) {
122         throw new CrudException("Invalid source/target/relationship type: " + key, Status.BAD_REQUEST);
123       }
124
125       Edge.Builder modelEdgeBuilder = new Edge.Builder(type);
126       
127       modelEdgeBuilder.source(new Vertex.Builder(sourceNodeType).id(sourceNodeId).build());
128       modelEdgeBuilder.target(new Vertex.Builder(targetNodeType).id(targetNodeId).build());
129
130       // validate it properties
131       validateEdgeProps(modelEdgeBuilder, payload.getProperties(), schemaObject);
132
133       return modelEdgeBuilder.build();
134     } catch (Exception ex) {
135       throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
136     }
137   }
138
139   public static Edge validateIncomingPatchPayload(Edge edge, String version, EdgePayload payload)
140               throws CrudException {
141             RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
142
143             try {
144                 if (payload.getSource() != null) {
145                         Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
146                         
147                         if (!sourceMatcher.matches()) {
148                                 throw new CrudException("Invalid Source Urls", Status.BAD_REQUEST);
149                         }
150                         String sourceNodeId = sourceMatcher.group(3);
151                         if (!sourceNodeId.equals(edge.getSource().getId().get())) {
152                                 throw new CrudException("Source can't be updated", Status.BAD_REQUEST);
153                         }
154                 }
155                 
156                 if (payload.getTarget() != null) {
157                         Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
158                          
159                         if (!targetMatcher.matches()) {
160                                 throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
161                         }
162                         String sourceNodeId = targetMatcher.group(3);
163                         if (!sourceNodeId.equals(edge.getTarget().getId().get())) {
164                                 throw new CrudException("Target can't be updated", Status.BAD_REQUEST);
165                         }
166                 }
167
168               // Remove the timestamp properties from the existing edge, as these should be managed by Champ.
169               Map<String,Object> existingProps = edge.getProperties();
170
171               if (existingProps.containsKey(Metadata.CREATED_TS.propertyName())) {
172                 existingProps.remove(Metadata.CREATED_TS.propertyName());
173               }
174               if (existingProps.containsKey(Metadata.UPDATED_TS.propertyName())) {
175                 existingProps.remove(Metadata.UPDATED_TS.propertyName());
176               }
177
178               // create key based on source:target:relationshipType
179               String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
180                   + ":" + edge.getType();
181
182               // find the validate the key from the schema
183               Map<String, Class<?>> schemaObject = schema.lookupRelation(key);
184
185               if (schemaObject == null) {
186                 Logger.warn("key :" + key
187                     + " not found in relationship schema . Skipping the schema validation");
188                 return edge;
189               }
190
191               Set<Map.Entry<String, JsonElement>> entries = payload.getProperties().getAsJsonObject().entrySet();
192
193               for (Map.Entry<String, JsonElement> entry : entries) {
194                   if (!schemaObject.containsKey(entry.getKey())) {
195                           throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST);
196                   } else if (entry.getValue() instanceof JsonNull && edge.getProperties().containsKey(entry.getKey())) {
197                           edge.getProperties().remove(entry.getKey());
198                   } else if (!(entry.getValue() instanceof JsonNull)) {
199                           Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(), schemaObject.get(entry.getKey()));
200                           edge.getProperties().put(entry.getKey(), value);
201                   }
202               }
203               
204           return edge;
205       } catch (Exception ex) {
206           throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
207       }
208   }
209
210
211   public static Edge validateIncomingUpdatePayload(Edge edge, String version, Vertex sourceNode, Vertex targetNode, JsonElement properties) 
212                   throws CrudException {
213           EdgePayload payload = new EdgePayload();
214           payload.setSource("services/inventory/" + version + "/" + sourceNode.getType() + "/" + sourceNode.getId().get());
215           payload.setTarget("services/inventory/" + version + "/" + targetNode.getType() + "/" + targetNode.getId().get());
216           payload.setType(edge.getType());
217           payload.setProperties(properties);
218           return validateIncomingUpdatePayload(edge, version, payload);
219   }
220
221   public static Edge validateIncomingUpdatePayload(Edge edge, String version, EdgePayload payload)
222       throws CrudException {
223     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
224
225     try {
226         if (payload.getSource() != null) {
227                 Matcher sourceMatcher = urlPattern.matcher(payload.getSource());
228                 
229                 if (!sourceMatcher.matches()) {
230                         throw new CrudException("Invalid Source Urls", Status.BAD_REQUEST);
231                 }
232                 String sourceNodeId = sourceMatcher.group(3);
233                 if (!sourceNodeId.equals(edge.getSource().getId().get())) {
234                         throw new CrudException("Source can't be updated", Status.BAD_REQUEST);
235                 }
236         }
237         
238         if (payload.getTarget() != null) {
239                 Matcher targetMatcher = urlPattern.matcher(payload.getTarget());
240                 
241                 if (!targetMatcher.matches()) {
242                         throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST);
243                 }
244                 String sourceNodeId = targetMatcher.group(3);
245                 if (!sourceNodeId.equals(edge.getTarget().getId().get())) {
246                         throw new CrudException("Target can't be updated", Status.BAD_REQUEST);
247                 }
248         }
249
250       // create key based on source:target:relationshipType
251       String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
252           + ":" + edge.getType();
253
254       // find the validate the key from the schema
255       Map<String, Class<?>> schemaObject = schema.lookupRelation(key);
256
257       if (schemaObject == null) {
258         Logger.warn("key :" + key
259             + " not found in relationship schema . Skipping the schema validation");
260         return edge;
261       }
262
263       Edge.Builder updatedEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId().get());
264       
265       updatedEdgeBuilder.source(new Vertex.Builder(edge.getSource().getType()).id(edge.getSource().getId().get()).build());
266       updatedEdgeBuilder.target(new Vertex.Builder(edge.getTarget().getType()).id(edge.getTarget().getId().get()).build());
267
268       validateEdgeProps(updatedEdgeBuilder, payload.getProperties(), schemaObject);
269
270       return updatedEdgeBuilder.build();
271     } catch (Exception ex) {
272       throw new CrudException(ex.getMessage(), Status.BAD_REQUEST);
273     }
274   }
275
276
277   private static void validateEdgeProps(Edge.Builder builder, JsonElement props, Map<String, Class<?>> schemaObject) throws CrudException {
278     Set<Map.Entry<String, JsonElement>> entries = props.getAsJsonObject().entrySet();
279
280     for (Map.Entry<String, JsonElement> entry : entries) {
281       if (!schemaObject.containsKey(entry.getKey())) {
282         throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST);
283       } else {
284         Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(),
285             schemaObject.get(entry.getKey()));
286         builder.property(entry.getKey(), value);
287       }
288     }
289   }
290
291   public static Edge validateOutgoingPayload(String version, Edge edge) throws CrudException {
292     Edge.Builder modelEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId()
293         .get()).source(edge.getSource())
294         .target(edge.getTarget());
295
296     RelationshipSchema schema = EdgeRulesLoader.getSchemaForVersion(version);
297
298     String key = edge.getSource().getType() + ":" + edge.getTarget().getType()
299         + ":" + edge.getType();
300     Map<String, Class<?>> schemaObject = schema.lookupRelation(key);
301
302     if (schemaObject == null || schemaObject.isEmpty()) {
303       return edge;
304     }
305
306     for (String prop : edge.getProperties().keySet()) {
307       if (schemaObject.containsKey(prop)) {
308         modelEdgeBuilder.property(prop, edge.getProperties().get(prop));
309       }
310
311     }
312     return modelEdgeBuilder.build();
313   }
314   
315   public static String vertexTypeFromUri(String uri) throws CrudException {
316
317           Matcher matcher = urlPattern.matcher(uri);
318           
319           if (!matcher.matches()) {
320                   throw new CrudException("Invalid Source/Target Urls", Status.BAD_REQUEST);
321           }
322           
323           return matcher.group(2);
324   }
325 }