Reformat catalog-model
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / tosca / validators / MapValidator.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.JsonSyntaxException;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.Set;
29 import org.apache.commons.lang.StringUtils;
30 import org.openecomp.sdc.be.config.BeEcompErrorManager;
31 import org.openecomp.sdc.be.model.DataTypeDefinition;
32 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
33 import org.openecomp.sdc.common.log.wrappers.Logger;
34 import org.openecomp.sdc.common.util.JsonUtils;
35
36 /*
37  * Property Type Map correct usage:
38  * null key null value = Yaml reader error
39 valid key null value = key & value deleted
40 duplicated keys = last key is taken
41 mismatch between inner type and values type = returned mismatch in data type
42 validators and converters works the same as before
43
44 Types:
45 when written line by line :
46                     key1 : val1
47                     key2 : val2
48 key1 and val does not need "    " , even if val1 is a string.
49 when written as one line : {"key1":val1 , "key2":val2}
50 Keys always need " " around them.
51 */
52 public class MapValidator implements PropertyTypeValidator {
53
54     private static final Logger log = Logger.getLogger(MapValidator.class.getName());
55     private static MapValidator mapValidator = new MapValidator();
56     private static DataTypeValidatorConverter dataTypeValidatorConverter = DataTypeValidatorConverter.getInstance();
57     private static JsonParser jsonParser = new JsonParser();
58
59     public static MapValidator getInstance() {
60         return mapValidator;
61     }
62
63     @Override
64     public boolean isValid(String value, String innerType, Map<String, DataTypeDefinition> allDataTypes) {
65         if (StringUtils.isEmpty(value)) {
66             return true;
67         }
68         if (innerType == null) {
69             return false;
70         }
71         PropertyTypeValidator innerValidator;
72         PropertyTypeValidator keyValidator = ToscaPropertyType.KEY.getValidator();
73         ToscaPropertyType innerToscaType = ToscaPropertyType.isValidType(innerType);
74         if (innerToscaType != null) {
75             switch (innerToscaType) {
76                 case STRING:
77                     innerValidator = ToscaPropertyType.STRING.getValidator();
78                     break;
79                 case INTEGER:
80                     innerValidator = ToscaPropertyType.INTEGER.getValidator();
81                     break;
82                 case FLOAT:
83                     innerValidator = ToscaPropertyType.FLOAT.getValidator();
84                     break;
85                 case BOOLEAN:
86                     innerValidator = ToscaPropertyType.BOOLEAN.getValidator();
87                     break;
88                 case JSON:
89                     innerValidator = ToscaPropertyType.JSON.getValidator();
90                     break;
91                 default:
92                     log.debug("inner Tosca Type is unknown. {}", innerToscaType);
93                     return false;
94             }
95         } else {
96             log.debug("inner Tosca Type is: {}", innerType);
97             boolean isValid = validateComplexInnerType(value, innerType, allDataTypes);
98             log.debug("Finish to validate value {} of map with inner type {}. result is {}", value, innerType, isValid);
99             return isValid;
100         }
101         try {
102             JsonElement jsonObject = jsonParser.parse(value);
103             if (!jsonObject.isJsonObject()) {
104                 return false;
105             }
106             JsonObject valueAsJson = jsonObject.getAsJsonObject();
107             return validateJsonObject(allDataTypes, innerValidator, keyValidator, valueAsJson);
108         } catch (JsonSyntaxException e) {
109             log.debug("Failed to parse json : {}", value, e);
110             BeEcompErrorManager.getInstance().logBeInvalidJsonInput("Map Validator");
111         }
112         return false;
113     }
114
115     private boolean validateJsonObject(Map<String, DataTypeDefinition> allDataTypes, PropertyTypeValidator innerValidator,
116                                        PropertyTypeValidator keyValidator, JsonObject asJsonObject) {
117         Set<Entry<String, JsonElement>> entrySet = asJsonObject.entrySet();
118         for (Entry<String, JsonElement> entry : entrySet) {
119             String currentKey = entry.getKey();
120             JsonElement jsonValue = entry.getValue();
121             String element = JsonUtils.toString(jsonValue);
122             if (!innerValidator.isValid(element, null, allDataTypes) || !keyValidator.isValid(entry.getKey(), null, allDataTypes)) {
123                 log.debug("validation of key : {}, element : {} failed", currentKey, entry.getValue());
124                 return false;
125             }
126         }
127         return true;
128     }
129
130     private boolean validateComplexInnerType(String value, String innerType, Map<String, DataTypeDefinition> allDataTypes) {
131         DataTypeDefinition innerDataTypeDefinition = allDataTypes.get(innerType);
132         if (innerDataTypeDefinition == null) {
133             log.debug("Data type {} cannot be found in our data types.", innerType);
134             return false;
135         }
136         try {
137             JsonElement jsonObject = jsonParser.parse(value);
138             JsonObject asJsonObject = jsonObject.getAsJsonObject();
139             Set<Entry<String, JsonElement>> entrySet = asJsonObject.entrySet();
140             for (Entry<String, JsonElement> entry : entrySet) {
141                 String currentKey = entry.getKey();
142                 JsonElement currentValue = entry.getValue();
143                 if (currentValue != null) {
144                     String element = JsonUtils.toString(currentValue);
145                     boolean isValid = dataTypeValidatorConverter.isValid(element, innerDataTypeDefinition, allDataTypes);
146                     if (!isValid) {
147                         log.debug("Cannot parse value {} from type {} of key {}", currentValue, innerType, currentKey);
148                         return false;
149                     }
150                 }
151             }
152         } catch (Exception e) {
153             log.debug("Cannot parse value {} of map from inner type {}", value, innerType, e);
154             return false;
155         }
156         return true;
157     }
158
159     @Override
160     public boolean isValid(String value, String innerType) {
161         return isValid(value, innerType, null);
162     }
163 }