31cec74f0d5c9576d3f7e03896fdbf353dd2cd47
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 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.openecomp.sdc.be.model.tosca.validators;
22
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Map.Entry;
27 import java.util.Set;
28
29 import org.apache.commons.lang3.tuple.ImmutablePair;
30 import org.openecomp.sdc.be.model.DataTypeDefinition;
31 import org.openecomp.sdc.be.model.PropertyDefinition;
32 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
33 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
34 import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import com.google.gson.Gson;
39 import com.google.gson.JsonElement;
40 import com.google.gson.JsonObject;
41 import com.google.gson.JsonParser;
42 import com.google.gson.JsonPrimitive;
43 import com.google.gson.JsonSyntaxException;
44
45 public class DataTypeValidatorConverter {
46
47         private static DataTypeValidatorConverter dataTypeValidatorConverter = new DataTypeValidatorConverter();
48
49         public static DataTypeValidatorConverter getInstance() {
50                 return dataTypeValidatorConverter;
51         }
52
53         private DataTypeValidatorConverter() {
54
55         }
56
57         private static Logger log = LoggerFactory.getLogger(DataTypeValidatorConverter.class.getName());
58
59         JsonParser jsonParser = new JsonParser();
60
61         ImmutablePair<JsonElement, Boolean> falseResult = new ImmutablePair<JsonElement, Boolean>(null, false);
62         ImmutablePair<JsonElement, Boolean> trueEmptyResult = new ImmutablePair<JsonElement, Boolean>(null, true);
63
64         ImmutablePair<String, Boolean> trueStringEmptyResult = new ImmutablePair<String, Boolean>(null, true);
65         ImmutablePair<String, Boolean> falseStringEmptyResult = new ImmutablePair<String, Boolean>(null, true);
66
67         private ToscaPropertyType isDataTypeDerviedFromScalarType(DataTypeDefinition dataTypeDef) {
68
69                 ToscaPropertyType result = null;
70
71                 DataTypeDefinition dataType = dataTypeDef;
72
73                 while (dataType != null) {
74
75                         String name = dataType.getName();
76                         ToscaPropertyType typeIfScalar = ToscaPropertyType.getTypeIfScalar(name);
77                         if (typeIfScalar != null) {
78                                 result = typeIfScalar;
79                                 break;
80                         }
81
82                         dataType = dataType.getDerivedFrom();
83                 }
84
85                 return result;
86         }
87
88         private ImmutablePair<JsonElement, Boolean> validateAndUpdate(JsonElement jsonElement, DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> allDataTypes) {
89
90                 Map<String, PropertyDefinition> allProperties = getAllProperties(dataTypeDefinition);
91
92                 ToscaPropertyType toscaPropertyType = null;
93                 if ((toscaPropertyType = isDataTypeDerviedFromScalarType(dataTypeDefinition)) != null) {
94
95                         PropertyTypeValidator validator = toscaPropertyType.getValidator();
96                         PropertyValueConverter converter = toscaPropertyType.getConverter();
97                         if (jsonElement == null || true == jsonElement.isJsonNull()) {
98                                 boolean valid = validator.isValid(null, null, allDataTypes);
99                                 if (!valid) {
100                                         log.trace("Failed in validation of property {} from type {}",  dataTypeDefinition.getName(), dataTypeDefinition.getName());
101                                         return falseResult;
102                                 }
103                                 return new ImmutablePair<JsonElement, Boolean>(jsonElement, true);
104
105                         } else {
106                                 if (jsonElement.isJsonPrimitive()) {
107                                         String value = null;
108                                         if (jsonElement != null) {
109                                                 if (jsonElement.toString().isEmpty()) {
110                                                         value = "";
111                                                 } else {
112                                                         value = jsonElement.toString();
113                                                 }
114                                         }
115                                         boolean valid = validator.isValid(value, null, null);
116                                         if (!valid) {
117                                                 log.trace("Failed in validation of property {} from type {}. Json primitive value is {}", dataTypeDefinition.getName(), dataTypeDefinition.getName(), value);
118                                                 return falseResult;
119                                         }
120
121                                         String convertedValue = converter.convert(value, null, allDataTypes);
122                                         JsonElement element = null;
123                                         try {
124                                                 element = jsonParser.parse(convertedValue);
125                                         } catch (JsonSyntaxException e) {
126                                                 log.debug("Failed to parse value {} of property {} {}", convertedValue, dataTypeDefinition.getName(), e);
127                                                 return falseResult;
128                                         }
129
130                                         return new ImmutablePair<JsonElement, Boolean>(element, true);
131
132                                 } else {
133                                         // MAP, LIST, OTHER types cannot be applied data type
134                                         // definition scalar type. We currently cannot derived from
135                                         // map/list. (cannot add the entry schema to it)
136                                         log.debug("We cannot derive from list/map. Thus, the value cannot be not primitive since the data type {} is scalar one", dataTypeDefinition.getName());
137
138                                         return falseResult;
139                                 }
140                         }
141                 } else {
142
143                         if (jsonElement == null || jsonElement.isJsonNull()) {
144
145                                 return new ImmutablePair<JsonElement, Boolean>(jsonElement, true);
146
147                         } else {
148
149                                 if (jsonElement.isJsonObject()) {
150
151                                         JsonObject buildJsonObject = new JsonObject();
152
153                                         JsonObject asJsonObject = jsonElement.getAsJsonObject();
154                                         Set<Entry<String, JsonElement>> entrySet = asJsonObject.entrySet();
155
156                                         for (Entry<String, JsonElement> entry : entrySet) {
157                                                 String propName = entry.getKey();
158
159                                                 JsonElement elementValue = entry.getValue();
160
161                                                 PropertyDefinition propertyDefinition = allProperties.get(propName);
162                                                 if (propertyDefinition == null) {
163                                                         log.debug("The property {} was not found under data type {}" ,propName, dataTypeDefinition.getName());
164                                                         return falseResult;
165                                                 }
166                                                 String type = propertyDefinition.getType();
167                                                 boolean isScalarType = ToscaPropertyType.isScalarType(type);
168
169                                                 if (isScalarType) {
170                                                         ToscaPropertyType propertyType = ToscaPropertyType.isValidType(type);
171                                                         if (propertyType == null) {
172                                                                 log.debug("cannot find the {} under default tosca property types", type);
173                                                                 return falseResult;
174                                                         }
175                                                         PropertyTypeValidator validator = propertyType.getValidator();
176                                                         String innerType = null;
177                                                         if (propertyType == ToscaPropertyType.LIST || propertyType == ToscaPropertyType.MAP) {
178                                                                 if (propertyDefinition.getSchema() != null && propertyDefinition.getSchema().getProperty() != null) {
179                                                                         innerType = propertyDefinition.getSchema().getProperty().getType();
180                                                                         if (innerType == null) {
181                                                                                 log.debug("Property type {} must have inner type in its declaration.", propertyType);
182                                                                                 return falseResult;
183                                                                         }
184                                                                 }
185                                                         }
186
187                                                         String value = null;
188                                                         if (elementValue != null) {
189                                                                 if (elementValue.isJsonPrimitive() && elementValue.getAsString().isEmpty()) {
190                                                                         value = "";
191                                                                 } else {
192                                                                         value = elementValue.toString();
193                                                                 }
194                                                         }
195
196                                                         boolean isValid = validator.isValid(value, innerType, allDataTypes);
197                                                         if (false == isValid) {
198                                                                 log.debug("Failed to validate the value {} from type {}", value, propertyType);
199                                                                 return falseResult;
200                                                         }
201
202                                                         PropertyValueConverter converter = propertyType.getConverter();
203                                                         String convertedValue = converter.convert(value, innerType, allDataTypes);
204
205                                                         JsonElement element = null;
206                                                         if (convertedValue != null) {
207                                                                 if (convertedValue.isEmpty()) {
208                                                                         element = new JsonPrimitive("");
209                                                                 } else {
210                                                                         try {
211                                                                                 element = jsonParser.parse(convertedValue);
212                                                                         } catch (JsonSyntaxException e) {
213                                                                                 log.debug("Failed to parse value {} of type {}", convertedValue, propertyType, e);
214                                                                                 return falseResult;
215                                                                         }
216                                                                 }
217                                                         }
218                                                         buildJsonObject.add(propName, element);
219
220                                                 } else {
221
222                                                         DataTypeDefinition typeDefinition = allDataTypes.get(type);
223                                                         if (typeDefinition == null) {
224                                                                 log.debug("The data type {} cannot be found in the given data type list.", type);
225                                                                 return falseResult;
226                                                         }
227
228                                                         ImmutablePair<JsonElement, Boolean> isValid = validateAndUpdate(elementValue, typeDefinition, allDataTypes);
229
230                                                         if (!isValid.getRight().booleanValue()) {
231                                                                 log.debug("Failed in validation of value {} from type {}", (elementValue != null ? elementValue.toString() : null), typeDefinition.getName());
232                                                                 return falseResult;
233                                                         }
234
235                                                         buildJsonObject.add(propName, isValid.getLeft());
236                                                 }
237
238                                         }
239
240                                         return new ImmutablePair<JsonElement, Boolean>(buildJsonObject, true);
241                                 } else {
242                                         log.debug("The value {} of type {} should be json object", (jsonElement != null ? jsonElement.toString() : null), dataTypeDefinition.getName());
243                                         return falseResult;
244                                 }
245
246                         }
247                 }
248
249         }
250
251         public ImmutablePair<JsonElement, Boolean> validateAndUpdate(String value, DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> allDataTypes) {
252
253                 ImmutablePair<JsonElement, Boolean> result = falseResult;
254
255                 if (value == null || value.isEmpty()) {
256                         return trueEmptyResult;
257                 }
258
259                 JsonElement jsonElement = null;
260                 try {
261                         jsonElement = jsonParser.parse(value);
262                 } catch (JsonSyntaxException e) {
263                         return falseResult;
264                 }
265
266                 result = validateAndUpdate(jsonElement, dataTypeDefinition, allDataTypes);
267
268                 return result;
269         }
270
271         private Map<String, PropertyDefinition> getAllProperties(DataTypeDefinition dataTypeDefinition) {
272
273                 Map<String, PropertyDefinition> allParentsProps = new HashMap<String, PropertyDefinition>();
274
275                 while (dataTypeDefinition != null) {
276
277                         List<PropertyDefinition> currentParentsProps = dataTypeDefinition.getProperties();
278                         if (currentParentsProps != null) {
279                                 currentParentsProps.stream().forEach(p -> allParentsProps.put(p.getName(), p));
280                         }
281
282                         dataTypeDefinition = dataTypeDefinition.getDerivedFrom();
283                 }
284
285                 return allParentsProps;
286         }
287
288         public boolean isValid(String value, DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> allDataTypes) {
289
290                 boolean result = false;
291
292                 if (value == null || value.isEmpty()) {
293                         return true;
294                 }
295
296                 JsonElement jsonElement = null;
297                 try {
298                         jsonElement = jsonParser.parse(value);
299                 } catch (JsonSyntaxException e) {
300                         log.debug("Failed to parse the value {} from type {}", value, dataTypeDefinition, e);
301                         return false;
302                 }
303
304                 result = isValid(jsonElement, dataTypeDefinition, allDataTypes);
305
306                 return result;
307         }
308
309         private boolean isValid(JsonElement jsonElement, DataTypeDefinition dataTypeDefinition, Map<String, DataTypeDefinition> allDataTypes) {
310
311                 Map<String, PropertyDefinition> allProperties = getAllProperties(dataTypeDefinition);
312
313                 ToscaPropertyType toscaPropertyType = null;
314                 if ((toscaPropertyType = isDataTypeDerviedFromScalarType(dataTypeDefinition)) != null) {
315
316                         PropertyTypeValidator validator = toscaPropertyType.getValidator();
317                         if (jsonElement == null || true == jsonElement.isJsonNull()) {
318                                 boolean valid = validator.isValid(null, null, allDataTypes);
319                                 if (false == valid) {
320                                         log.trace("Failed in validation of property {} from type {}", dataTypeDefinition.getName(), dataTypeDefinition.getName());
321                                         return false;
322                                 }
323
324                                 return true;
325
326                         } else {
327                                 if (true == jsonElement.isJsonPrimitive()) {
328                                         String value = null;
329                                         if (jsonElement != null) {
330                                                 if (jsonElement.toString().isEmpty()) {
331                                                         value = "";
332                                                 } else {
333                                                         value = jsonElement.toString();
334                                                 }
335                                         }
336                                         boolean valid = validator.isValid(value, null, allDataTypes);
337                                         if (false == valid) {
338                                                 log.trace("Failed in validation of property {} from type {}. Json primitive value is {}", dataTypeDefinition.getName(), dataTypeDefinition.getName(), value);
339                                                 return false;
340                                         }
341
342                                         return true;
343
344                                 } else {
345                                         // MAP, LIST, OTHER types cannot be applied data type
346                                         // definition scalar type. We currently cannot derived from
347                                         // map/list. (cannot add the entry schema to it)
348                                         log.debug("We cannot derive from list/map. Thus, the value cannot be not primitive since the data type {} is scalar one", dataTypeDefinition.getName());
349
350                                         return false;
351                                 }
352                         }
353                 } else {
354
355                         if (jsonElement == null || jsonElement.isJsonNull()) {
356
357                                 return true;
358
359                         } else {
360
361                                 if (jsonElement.isJsonObject()) {
362
363                                         JsonObject asJsonObject = jsonElement.getAsJsonObject();
364                                         Set<Entry<String, JsonElement>> entrySet = asJsonObject.entrySet();
365
366                                         for (Entry<String, JsonElement> entry : entrySet) {
367                                                 String propName = entry.getKey();
368
369                                                 JsonElement elementValue = entry.getValue();
370
371                                                 PropertyDefinition propertyDefinition = allProperties.get(propName);
372                                                 if (propertyDefinition == null) {
373                                                         log.debug("The property {} was not found under data type {}", propName, dataTypeDefinition.getName());
374                                                         return false;
375                                                 }
376                                                 String type = propertyDefinition.getType();
377                                                 boolean isScalarType = ToscaPropertyType.isScalarType(type);
378
379                                                 if (true == isScalarType) {
380                                                         ToscaPropertyType propertyType = ToscaPropertyType.isValidType(type);
381                                                         if (propertyType == null) {
382                                                                 log.debug("cannot find the {} under default tosca property types", type);
383                                                                 return false;
384                                                         }
385                                                         PropertyTypeValidator validator = propertyType.getValidator();
386                                                         String innerType = null;
387                                                         if (propertyType == ToscaPropertyType.LIST || propertyType == ToscaPropertyType.MAP) {
388                                                                 if (propertyDefinition.getSchema() != null && propertyDefinition.getSchema().getProperty() != null) {
389                                                                         innerType = propertyDefinition.getSchema().getProperty().getType();
390                                                                         if (innerType == null) {
391                                                                                 log.debug("Property type {} must have inner type in its declaration.", propertyType);
392                                                                                 return false;
393                                                                         }
394                                                                 }
395                                                         }
396
397                                                         String value = null;
398                                                         if (elementValue != null) {
399                                                                 if (elementValue.isJsonPrimitive() && elementValue.getAsString().isEmpty()) {
400                                                                         value = "";
401                                                                 } else {
402                                                                         value = elementValue.toString();
403                                                                 }
404                                                         }
405
406                                                         boolean isValid = validator.isValid(value, innerType, allDataTypes);
407                                                         if (false == isValid) {
408                                                                 log.debug("Failed to validate the value {} from type {}", value, propertyType);
409                                                                 return false;
410                                                         }
411
412                                                 } else {
413
414                                                         DataTypeDefinition typeDefinition = allDataTypes.get(type);
415                                                         if (typeDefinition == null) {
416                                                                 log.debug("The data type {} cannot be found in the given data type list.", type);
417                                                                 return false;
418                                                         }
419
420                                                         boolean isValid = isValid(elementValue, typeDefinition, allDataTypes);
421
422                                                         if (false == isValid) {
423                                                                 log.debug("Failed in validation of value {} from type {}", (elementValue != null ? elementValue.toString() : null), typeDefinition.getName());
424                                                                 return false;
425                                                         }
426
427                                                 }
428
429                                         }
430
431                                         return true;
432                                 } else {
433                                         log.debug("The value {} of type {} should be json object", (jsonElement != null ? jsonElement.toString() : null), dataTypeDefinition.getName());
434                                         return false;
435                                 }
436
437                         }
438                 }
439
440         }
441 }