Catalog alignment
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / tosca / converters / MapConverter.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.converters;
22
23 import com.google.common.base.Strings;
24 import com.google.gson.*;
25 import fj.data.Either;
26 import org.apache.commons.lang3.tuple.ImmutablePair;
27 import org.openecomp.sdc.be.config.BeEcompErrorManager;
28 import org.openecomp.sdc.be.model.DataTypeDefinition;
29 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
30 import org.openecomp.sdc.be.model.tosca.validators.DataTypeValidatorConverter;
31 import org.openecomp.sdc.be.model.tosca.validators.ListValidator;
32 import org.openecomp.sdc.common.log.wrappers.Logger;
33 import org.openecomp.sdc.common.util.GsonFactory;
34 import org.openecomp.sdc.common.util.JsonUtils;
35
36 import java.util.HashMap;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.Set;
40
41 public class MapConverter implements PropertyValueConverter {
42
43     private static MapConverter mapConverter = new MapConverter();
44     private static Gson gson = GsonFactory.getGson();
45     private static final Logger log = Logger.getLogger(ListValidator.class.getName());
46
47     DataTypeValidatorConverter dataTypeValidatorConverter = DataTypeValidatorConverter.getInstance();
48
49     private static JsonParser jsonParser = new JsonParser();
50
51     public static MapConverter getInstance() {
52         return mapConverter;
53     }
54
55     public String convert(String value, String innerType, Map<String, DataTypeDefinition> dataTypes) {
56
57         Either<String, Boolean> convertWithErrorResult = this.convertWithErrorResult(value, innerType, dataTypes);
58         if (convertWithErrorResult.isRight()) {
59             return null;
60         }
61
62         return convertWithErrorResult.left().value();
63     }
64
65     public Either<String, Boolean> convertWithErrorResult(String value, String innerType,
66             Map<String, DataTypeDefinition> dataTypes) {
67
68         if (Strings.isNullOrEmpty(value) || innerType == null) {
69             return Either.left(value);
70         }
71
72         PropertyValueConverter innerConverter;
73         PropertyValueConverter keyConverter = ToscaPropertyType.STRING.getConverter();
74         ToscaPropertyType innerToscaType = ToscaPropertyType.isValidType(innerType);
75
76         if (innerToscaType != null) {
77             switch (innerToscaType) {
78             case STRING:
79                 innerConverter = ToscaPropertyType.STRING.getConverter();
80                 break;
81             case INTEGER:
82                 innerConverter = ToscaPropertyType.INTEGER.getConverter();
83                 break;
84             case FLOAT:
85                 innerConverter = ToscaPropertyType.FLOAT.getConverter();
86                 break;
87             case BOOLEAN:
88                 innerConverter = ToscaPropertyType.BOOLEAN.getConverter();
89                 break;
90             case JSON:
91                 innerConverter = ToscaPropertyType.JSON.getConverter();
92                 break;
93             default:
94                 log.debug("inner Tosca Type is unknown");
95                 return Either.left(value);
96             }
97
98         } else {
99
100             log.debug("inner Tosca Type {} ia a complex data type.", innerType);
101
102             return convertComplexInnerType(value, innerType, keyConverter,
103                     dataTypes);
104
105         }
106
107         try {
108             Map<String, String> newMap = new HashMap<>();
109
110             JsonElement jsonObject = jsonParser.parse(value);
111             JsonObject asJsonObject = jsonObject.getAsJsonObject();
112             Set<Entry<String, JsonElement>> entrySet = asJsonObject.entrySet();
113             for (Entry<String, JsonElement> entry : entrySet) {
114                 String key = entry.getKey();
115                 JsonElement jsonValue = entry.getValue();
116
117                 key = keyConverter.convert(entry.getKey(), null, dataTypes);
118
119                 String element = JsonUtils.toString(jsonValue);
120
121                 String val = innerConverter.convert(element, null, dataTypes);
122                 newMap.put(key, val);
123             }
124
125             String objVal;
126             switch (innerToscaType) {
127             case STRING:
128                 value = gson.toJson(newMap);
129                 break;
130             case INTEGER:
131                 String key = null;
132                 Map<String, Integer> intMap = new HashMap<>();
133                 for (Map.Entry<String, String> entry : newMap.entrySet()) {
134                     objVal = entry.getValue();
135                     key = entry.getKey();
136                     if (objVal != null) {
137                         intMap.put(key, Integer.valueOf(objVal.toString()));
138                     } else {
139                         intMap.put(key, null);
140                     }
141
142                 }
143                 value = gson.toJson(intMap);
144                 break;
145             case FLOAT:
146                 value = "{";
147                 for (Map.Entry<String, String> entry : newMap.entrySet()) {
148                     objVal = entry.getValue();
149                     if (objVal == null) {
150                         objVal = "null";
151                     }
152                     key = entry.getKey();
153                     value += "\"" + key + "\":" + objVal.toString() + ",";
154                 }
155                 value = value.substring(0, value.length() - 1);
156                 value += "}";
157                 break;
158             case BOOLEAN:
159                 Map<String, Boolean> boolMap = new HashMap<>();
160                 for (Map.Entry<String, String> entry : newMap.entrySet()) {
161                     objVal = entry.getValue();
162                     key = entry.getKey();
163                     if (objVal != null) {
164                         boolMap.put(key, Boolean.valueOf(objVal.toString()));
165                     } else {
166                         boolMap.put(key, null);
167                     }
168                 }
169                 value = gson.toJson(boolMap);
170                 break;
171             default:
172                 value = gson.toJson(newMap);
173                 log.debug("inner Tosca Type unknown : {}", innerToscaType);
174             }
175         } catch (JsonParseException e) {
176             log.debug("Failed to parse json : {}", value, e);
177             BeEcompErrorManager.getInstance().logBeInvalidJsonInput("Map Converter");
178             return Either.right(false);
179         }
180
181         return Either.left(value);
182
183     }
184
185     /**
186      * convert the json value of map when the inner type is a complex data type
187      *
188      * @param value
189      * @param innerType
190      * @param keyConverter
191      * @param allDataTypes
192      * @return
193      */
194     private Either<String, Boolean> convertComplexInnerType(String value, String innerType,
195             PropertyValueConverter keyConverter, Map<String, DataTypeDefinition> allDataTypes) {
196
197         DataTypeDefinition dataTypeDefinition = allDataTypes.get(innerType);
198         if (dataTypeDefinition == null) {
199             log.debug("Cannot find data type {}", innerType);
200             return Either.right(false);
201         }
202
203         Map<String, JsonElement> newMap = new HashMap<>();
204
205         try {
206
207             JsonElement jsonObject = jsonParser.parse(value);
208             JsonObject asJsonObject = jsonObject.getAsJsonObject();
209             Set<Entry<String, JsonElement>> entrySet = asJsonObject.entrySet();
210             for (Entry<String, JsonElement> entry : entrySet) {
211                 String currentKey = keyConverter.convert(entry.getKey(), null, allDataTypes);
212
213                 JsonElement currentValue = entry.getValue();
214
215                 if (currentValue != null) {
216
217                     String element = JsonUtils.toString(currentValue);
218
219                     ImmutablePair<JsonElement, Boolean> validateAndUpdate = dataTypeValidatorConverter
220                             .validateAndUpdate(element, dataTypeDefinition, allDataTypes);
221                     if (!validateAndUpdate.right.booleanValue()) {
222                         log.debug("Cannot parse value {} from type {} of key {}",currentValue,innerType,currentKey);
223                         return Either.right(false);
224                     }
225                     JsonElement newValue = validateAndUpdate.left;
226                     newMap.put(currentKey, newValue);
227                 } else {
228                     newMap.put(currentKey, null);
229                 }
230             }
231
232         } catch (Exception e) {
233             log.debug("Cannot parse value {} of map from inner type {}", value, innerType);
234             return Either.right(false);
235         }
236
237         value = gson.toJson(newMap);
238         return Either.left(value);
239     }
240
241 }