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