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