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