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