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