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