Sync Integ to Master
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / ImportUtils.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.components.impl;
22
23 import com.google.gson.Gson;
24 import com.google.gson.GsonBuilder;
25 import com.google.gson.reflect.TypeToken;
26 import fj.data.Either;
27 import org.apache.commons.lang3.StringEscapeUtils;
28 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
29 import org.openecomp.sdc.be.model.HeatParameterDefinition;
30 import org.openecomp.sdc.be.model.InputDefinition;
31 import org.openecomp.sdc.be.model.LifecycleStateEnum;
32 import org.openecomp.sdc.be.model.PropertyConstraint;
33 import org.openecomp.sdc.be.model.PropertyDefinition;
34 import org.openecomp.sdc.be.model.heat.HeatParameterType;
35 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser;
36 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
37 import org.openecomp.sdc.common.api.ArtifactTypeEnum;
38 import org.springframework.beans.factory.config.YamlProcessor;
39 import org.yaml.snakeyaml.DumperOptions;
40 import org.yaml.snakeyaml.Yaml;
41 import org.yaml.snakeyaml.constructor.Constructor;
42 import org.yaml.snakeyaml.nodes.Tag;
43 import org.yaml.snakeyaml.representer.Representer;
44 import org.yaml.snakeyaml.resolver.Resolver;
45
46 import java.lang.reflect.Type;
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.HashMap;
51 import java.util.Iterator;
52 import java.util.LinkedHashMap;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Map.Entry;
56 import java.util.function.Consumer;
57 import java.util.function.Function;
58
59 public final class ImportUtils {
60     private ImportUtils() {
61
62     }
63
64     private static CustomResolver customResolver = new CustomResolver();
65     private static Yaml STRICT_MAPPING_YAML_LOADER =  new YamlLoader().getStrictYamlLoader();
66
67     private static class CustomResolver extends Resolver {
68         @Override
69         protected void addImplicitResolvers() {
70             // avoid implicit resolvers for strings that can be interpreted as boolean values
71             addImplicitResolver(Tag.STR, EMPTY, "");
72             addImplicitResolver(Tag.STR, NULL, null);
73             addImplicitResolver(Tag.NULL, NULL, "~nN\0");
74             addImplicitResolver(Tag.NULL, EMPTY, null);
75             addImplicitResolver(Tag.INT, INT, "-+0123456789");
76             addImplicitResolver(Tag.FLOAT, FLOAT, "-+0123456789.");
77             addImplicitResolver(Tag.YAML, YAML, "!&*");
78         }
79     }
80
81
82     private static void buildMap(Map<String, Object> output, Map<String, Object> map) {
83         for (Entry<String, Object> entry : map.entrySet()) {
84             String key = entry.getKey();
85             Object value = entry.getValue();
86             if (value instanceof Map) {
87                 Map<String, Object> result = new LinkedHashMap<>();
88                 buildMap(result, (Map) value);
89                 output.put(key, result);
90             }
91             else if (value instanceof Collection) {
92                 Map<String, Object> result = new LinkedHashMap<>();
93                 int i = 0;
94                 for(Object item : (Collection<Object>) value) {
95                     buildMap(result, Collections.singletonMap("[" + (i++) + "]", item));
96                 }
97                 output.put(key, new ArrayList<>(result.values()));
98             }
99             else {
100                 output.put(key, value);
101             }
102         }
103     }
104
105     public static Map<String, Object> loadYamlAsStrictMap(String content){
106         Map<String, Object> result = new LinkedHashMap<>();
107         Object map = STRICT_MAPPING_YAML_LOADER.load(content);
108         buildMap(result, (Map<String, Object>)map);
109         return result;
110     }
111
112     private static class YamlLoader extends YamlProcessor {
113         public Yaml getStrictYamlLoader() {
114             return createYaml();
115         }
116     }
117
118     @SuppressWarnings("unchecked")
119     public static Either<List<HeatParameterDefinition>, ResultStatusEnum> getHeatParamsWithoutImplicitTypes(String heatDecodedPayload, String artifactType) {
120         Map<String, Object> heatData = (Map<String, Object>) new Yaml(new Constructor(), new Representer(), new DumperOptions(), customResolver).load(heatDecodedPayload);
121         return getHeatParameters(heatData, artifactType);
122     }
123
124     public static class Constants {
125
126         public static final String FIRST_CERTIFIED_VERSION_VERSION = "1.0";
127         public static final String FIRST_NON_CERTIFIED_VERSION = "0.1";
128         public static final String VENDOR_NAME = "ATT (Tosca)";
129         public static final String VENDOR_RELEASE = "1.0.0.wd03";
130         public static final LifecycleStateEnum NORMATIVE_TYPE_LIFE_CYCLE = LifecycleStateEnum.CERTIFIED;
131         public static final LifecycleStateEnum NORMATIVE_TYPE_LIFE_CYCLE_NOT_CERTIFIED_CHECKOUT = LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT;
132         public static final boolean NORMATIVE_TYPE_HIGHEST_VERSION = true;
133         public static final String ABSTRACT_CATEGORY_NAME = "Generic";
134         public static final String ABSTRACT_SUBCATEGORY = "Abstract";
135         public static final String DEFAULT_ICON = "defaulticon";
136         public static final String INNER_VFC_DESCRIPTION = "Not reusable inner VFC";
137         public static final String USER_DEFINED_RESOURCE_NAMESPACE_PREFIX = "org.openecomp.resource.";
138         public static final String UI_JSON_PAYLOAD_NAME = "payloadName";
139         public static final String CVFC_DESCRIPTION = "Complex node type that is used as nested type in VF";
140     }
141
142     public enum ResultStatusEnum {
143         ELEMENT_NOT_FOUND, GENERAL_ERROR, OK, INVALID_PROPERTY_DEFAULT_VALUE, INVALID_PROPERTY_TYPE, INVALID_PROPERTY_VALUE, MISSING_ENTRY_SCHEMA_TYPE, INVALID_PROPERTY_NAME
144     }
145
146     public enum ToscaElementTypeEnum {
147         BOOLEAN, STRING, MAP, LIST, ALL
148     }
149
150     public enum ToscaTagNamesEnum {
151         DERIVED_FROM("derived_from"), IS_PASSWORD("is_password"),
152         // Properties
153         PROPERTIES("properties"), TYPE("type"), STATUS("status"), ENTRY_SCHEMA("entry_schema"), REQUIRED("required"), DESCRIPTION("description"), DEFAULT_VALUE("default"), VALUE("value"), CONSTRAINTS("constraints"),
154         // Group Types
155         MEMBERS("members"), METADATA("metadata"),
156         // Policy Types
157         TARGETS("targets"),
158         // Capabilities
159         CAPABILITIES("capabilities"), VALID_SOURCE_TYPES("valid_source_types"),
160         // Requirements
161         REQUIREMENTS("requirements"), NODE("node"), RELATIONSHIP("relationship"), CAPABILITY("capability"), INTERFACES("interfaces"),
162         // Heat env Validation
163         PARAMETERS("parameters"),
164         // Import Validations
165         TOSCA_VERSION("tosca_definitions_version"), TOPOLOGY_TEMPLATE("topology_template"), NODE_TYPES("node_types"), OCCURRENCES("occurrences"), NODE_TEMPLATES("node_templates"), GROUPS("groups"), INPUTS("inputs"),
166         SUBSTITUTION_MAPPINGS("substitution_mappings"),  NODE_TYPE("node_type"),
167         // Attributes
168         ATTRIBUTES("attributes"), LABEL("label"), HIDDEN("hidden"), IMMUTABLE("immutable"), GET_INPUT("get_input");
169
170         private String elementName;
171
172         private ToscaTagNamesEnum(String elementName) {
173             this.elementName = elementName;
174         }
175
176         public String getElementName() {
177             return elementName;
178         }
179     }
180
181     @SuppressWarnings("unchecked")
182     private static void handleElementNameNotFound(String elementName, Object elementValue, ToscaElementTypeEnum elementType, List<Object> returnedList) {
183         if (elementValue instanceof Map) {
184             ImportUtils.findToscaElements((Map<String, Object>) elementValue, elementName, elementType, returnedList);
185         } else if (elementValue instanceof List) {
186             ImportUtils.findAllToscaElementsInList((List<Object>) elementValue, elementName, elementType, returnedList);
187         }
188     }
189
190     @SuppressWarnings("unchecked")
191     private static void handleElementNameFound(String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList, Object elementValue) {
192
193         if (elementValue instanceof Boolean) {
194             if (elementType == ToscaElementTypeEnum.BOOLEAN || elementType == ToscaElementTypeEnum.ALL) {
195                 returnedList.add(elementValue);
196             }
197         }
198
199         else if (elementValue instanceof String) {
200             if (elementType == ToscaElementTypeEnum.STRING || elementType == ToscaElementTypeEnum.ALL) {
201                 returnedList.add(elementValue);
202             }
203         } else if (elementValue instanceof Map) {
204             if (elementType == ToscaElementTypeEnum.MAP || elementType == ToscaElementTypeEnum.ALL) {
205                 returnedList.add(elementValue);
206             }
207             ImportUtils.findToscaElements((Map<String, Object>) elementValue, elementName, elementType, returnedList);
208
209         } else if (elementValue instanceof List) {
210             if (elementType == ToscaElementTypeEnum.LIST || elementType == ToscaElementTypeEnum.ALL) {
211                 returnedList.add(elementValue);
212             }
213             ImportUtils.findAllToscaElementsInList((List<Object>) elementValue, elementName, elementType, returnedList);
214
215         }
216         // For Integer, Double etc...
217         else if (elementType == ToscaElementTypeEnum.ALL) {
218             if (elementValue != null) {
219                 returnedList.add(String.valueOf(elementValue));
220             }
221         }
222     }
223
224     private static void findAllToscaElementsInList(List<Object> list, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) {
225         Iterator<Object> listItr = list.iterator();
226         while (listItr.hasNext()) {
227             Object elementValue = listItr.next();
228             handleElementNameNotFound(elementName, elementValue, elementType, returnedList);
229         }
230
231     }
232
233     public static Either<Object, ResultStatusEnum> findToscaElement(Map<String, Object> toscaJson, ToscaTagNamesEnum elementName, ToscaElementTypeEnum elementType) {
234         List<Object> foundElements = new ArrayList<>();
235         Either<Object, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
236         ImportUtils.findToscaElements(toscaJson, elementName.getElementName(), elementType, foundElements);
237         if (foundElements.size() > 0) {
238             returnedElement = Either.left(foundElements.get(0));
239         }
240         return returnedElement;
241
242     }
243
244     /**
245      * Recursively searches for all tosca elements with key equals to elementName and value equals to elementType. <br>
246      * Returns Either element with:<br>
247      * List with all value if values found<br>
248      * Or ELEMENT_NOT_FOUND ActionStatus
249      *
250      * @param toscaJson
251      * @param toscaTagName
252      * @return
253      */
254     public static Either<List<Object>, ResultStatusEnum> findToscaElements(Map<String, Object> toscaJson, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) {
255         Either<List<Object>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
256         String skipKey = null;
257         if (toscaJson.containsKey(elementName)) {
258             Object elementValue = toscaJson.get(elementName);
259             handleElementNameFound(elementName, elementType, returnedList, elementValue);
260             skipKey = elementName;
261         }
262
263         Iterator<Entry<String, Object>> keyValItr = toscaJson.entrySet().iterator();
264         while (keyValItr.hasNext()) {
265             Entry<String, Object> keyValEntry = keyValItr.next();
266             if (!String.valueOf(keyValEntry.getKey()).equals(skipKey)) {
267                 handleElementNameNotFound(elementName, keyValEntry.getValue(), elementType, returnedList);
268             }
269         }
270
271         if (returnedList.size() > 0) {
272             returnedElement = Either.left(returnedList);
273         }
274
275         return returnedElement;
276     }
277
278     @SuppressWarnings("unchecked")
279     public static <T> Either<List<T>, ResultStatusEnum> findFirstToscaListElement(Map<String, Object> toscaJson, ToscaTagNamesEnum toscaTagName) {
280         Either<List<T>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
281         Either<Object, ResultStatusEnum> findFirstToscaElement = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.LIST);
282         if (findFirstToscaElement.isLeft()) {
283             returnedElement = Either.left((List<T>) findFirstToscaElement.left().value());
284         }
285         return returnedElement;
286
287     }
288
289     @SuppressWarnings("unchecked")
290     public static <T> Either<Map<String, T>, ResultStatusEnum> findFirstToscaMapElement(Map<String, Object> toscaJson, ToscaTagNamesEnum toscaTagName) {
291         Either<Map<String, T>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
292         Either<Object, ResultStatusEnum> findFirstToscaElement = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.MAP);
293         if (findFirstToscaElement.isLeft()) {
294             returnedElement = Either.left((Map<String, T>) findFirstToscaElement.left().value());
295         }
296         return returnedElement;
297
298     }
299
300     public static Either<String, ResultStatusEnum> findFirstToscaStringElement(Map<String, Object> toscaJson, ToscaTagNamesEnum toscaTagName) {
301         Either<String, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
302         Either<Object, ResultStatusEnum> findFirstToscaElements = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.STRING);
303         if (findFirstToscaElements.isLeft()) {
304             returnedElement = Either.left((String) findFirstToscaElements.left().value());
305         }
306         return returnedElement;
307     }
308
309     /**
310      * searches for first Tosca in Json map (toscaJson) boolean element by name (toscaTagName) returns found element or ELEMENT_NOT_FOUND status
311      *
312      * @param toscaJson
313      * @param toscaTagName
314      * @return
315      */
316     public static Either<String, ResultStatusEnum> findFirstToscaBooleanElement(Map<String, Object> toscaJson, ToscaTagNamesEnum toscaTagName) {
317         Either<String, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
318         Either<Object, ResultStatusEnum> findFirstToscaElements = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.BOOLEAN);
319         if (findFirstToscaElements.isLeft()) {
320             returnedElement = Either.left(String.valueOf(findFirstToscaElements.left().value()));
321         }
322         return returnedElement;
323     }
324
325     private static void setPropertyConstraints(Map<String, Object> propertyValue, PropertyDefinition property) {
326         Either<List<Object>, ResultStatusEnum> propertyFieldconstraints = findFirstToscaListElement(propertyValue, ToscaTagNamesEnum.CONSTRAINTS);
327         if (propertyFieldconstraints.isLeft()) {
328             List<Object> jsonConstraintList = propertyFieldconstraints.left().value();
329
330             List<PropertyConstraint> constraintList = new ArrayList<>();
331             Type constraintType = new TypeToken<PropertyConstraint>() {
332             }.getType();
333             Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create();
334
335             for (Object constraintJson : jsonConstraintList) {
336                 PropertyConstraint propertyConstraint = gson.fromJson(gson.toJson(constraintJson), constraintType);
337                 constraintList.add(propertyConstraint);
338             }
339             property.setConstraints(constraintList);
340         }
341     }
342
343     public static PropertyDefinition createModuleProperty(Map<String, Object> propertyValue) {
344
345         PropertyDefinition propertyDef = new PropertyDefinition();
346         ImportUtils.setField(propertyValue, ToscaTagNamesEnum.TYPE, type -> propertyDef.setType(type));
347         ImportUtils.setPropertyFieldRequired(propertyValue, propertyDef);
348         ImportUtils.setField(propertyValue, ToscaTagNamesEnum.DESCRIPTION, desc -> propertyDef.setDescription(desc));
349
350         Either<Object, ResultStatusEnum> findToscaElement = ImportUtils.findToscaElement(propertyValue, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL);
351         if (findToscaElement.isLeft()) {
352             String propertyJsonStringValue = getPropertyJsonStringValue(findToscaElement.left().value(), propertyDef.getType());
353             propertyDef.setDefaultValue(propertyJsonStringValue);
354         }
355         ImportUtils.setField(propertyValue, ToscaTagNamesEnum.IS_PASSWORD, pass -> propertyDef.setPassword(Boolean.parseBoolean(pass)));
356         ImportUtils.setField(propertyValue, ToscaTagNamesEnum.STATUS, status -> propertyDef.setStatus(status));
357         ImportUtils.setPropertyScheme(propertyValue, propertyDef);
358         ImportUtils.setPropertyConstraints(propertyValue, propertyDef);
359
360         return propertyDef;
361     }
362
363     public static InputDefinition createModuleInput(Map<String, Object> inputValue) {
364
365         InputDefinition inputDef = new InputDefinition();
366         ImportUtils.setField(inputValue, ToscaTagNamesEnum.TYPE, type -> inputDef.setType(type));
367         ImportUtils.setField(inputValue, ToscaTagNamesEnum.REQUIRED, req -> inputDef.setRequired(Boolean.parseBoolean(req)));
368         ImportUtils.setField(inputValue, ToscaTagNamesEnum.DESCRIPTION, desc -> inputDef.setDescription(desc));
369
370         Either<Object, ResultStatusEnum> findToscaElement = ImportUtils.findToscaElement(inputValue, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL);
371         if (findToscaElement.isLeft()) {
372             String propertyJsonStringValue = getPropertyJsonStringValue(findToscaElement.left().value(), inputDef.getType());
373             inputDef.setDefaultValue(propertyJsonStringValue);
374         }
375         ImportUtils.setField(inputValue, ToscaTagNamesEnum.IS_PASSWORD, pass -> inputDef.setPassword(Boolean.parseBoolean(pass)));
376         ImportUtils.setField(inputValue, ToscaTagNamesEnum.STATUS, status -> inputDef.setStatus(status));
377         ImportUtils.setField(inputValue, ToscaTagNamesEnum.LABEL, label -> inputDef.setLabel(label));
378         ImportUtils.setField(inputValue, ToscaTagNamesEnum.HIDDEN, hidden -> inputDef.setHidden(Boolean.parseBoolean(hidden)));
379         ImportUtils.setField(inputValue, ToscaTagNamesEnum.HIDDEN, immutable -> inputDef.setImmutable(Boolean.parseBoolean(immutable)));
380         ImportUtils.setField(inputValue, ToscaTagNamesEnum.LABEL, label -> inputDef.setLabel(label));
381         ImportUtils.setPropertyScheme(inputValue, inputDef);
382         ImportUtils.setPropertyConstraints(inputValue, inputDef);
383
384         return inputDef;
385     }
386
387     public static PropertyDefinition createModuleAttribute(Map<String, Object> attributeMap) {
388
389         PropertyDefinition attributeDef = new PropertyDefinition();
390         ImportUtils.setField(attributeMap, ToscaTagNamesEnum.TYPE, type -> attributeDef.setType(type));
391         ImportUtils.setField(attributeMap, ToscaTagNamesEnum.DESCRIPTION, desc -> attributeDef.setDescription(desc));
392         ImportUtils.setField(attributeMap, ToscaTagNamesEnum.STATUS, status -> attributeDef.setStatus(status));
393         Either<Object, ResultStatusEnum> eitherDefaultValue = ImportUtils.findToscaElement(attributeMap, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL);
394         if (eitherDefaultValue.isLeft()) {
395             String attributeDefaultValue = getPropertyJsonStringValue(eitherDefaultValue.left().value(), attributeDef.getType());
396             attributeDef.setDefaultValue(attributeDefaultValue);
397         }
398         Either<Object, ResultStatusEnum> eitherValue = ImportUtils.findToscaElement(attributeMap, ToscaTagNamesEnum.VALUE, ToscaElementTypeEnum.ALL);
399         if (eitherValue.isLeft()) {
400             String attributeValue = getPropertyJsonStringValue(eitherValue.left().value(), attributeDef.getType());
401             attributeDef.setValue(attributeValue);
402         }
403         ImportUtils.setAttributeScheme(attributeMap, attributeDef);
404         return attributeDef;
405     }
406
407     private static void setPropertyScheme(Map<String, Object> propertyValue, PropertyDefinition propertyDefinition) {
408         Either<SchemaDefinition, ResultStatusEnum> eitherSchema = getSchema(propertyValue);
409         if (eitherSchema.isLeft()) {
410             SchemaDefinition schemaDef = new SchemaDefinition();
411             schemaDef.setProperty(eitherSchema.left().value().getProperty());
412             propertyDefinition.setSchema(schemaDef);
413         }
414
415     }
416
417     private static void setAttributeScheme(Map<String, Object> propertyValue, PropertyDefinition propertyDefinition) {
418         Either<SchemaDefinition, ResultStatusEnum> eitherSchema = getSchema(propertyValue);
419         if (eitherSchema.isLeft()) {
420             SchemaDefinition schemaDef = new SchemaDefinition();
421             schemaDef.setProperty(eitherSchema.left().value().getProperty());
422             propertyDefinition.setSchema(schemaDef);
423         }
424
425     }
426
427     private static Either<SchemaDefinition, ResultStatusEnum> getSchema(Map<String, Object> propertyValue) {
428         Either<SchemaDefinition, ResultStatusEnum> result = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
429         Either<Object, ResultStatusEnum> propertyFieldEntryScheme = findToscaElement(propertyValue, ToscaTagNamesEnum.ENTRY_SCHEMA, ToscaElementTypeEnum.ALL);
430         if (propertyFieldEntryScheme.isLeft()) {
431             if (propertyFieldEntryScheme.left().value() instanceof String) {
432                 String schemaType = (String) propertyFieldEntryScheme.left().value();
433                 SchemaDefinition schema = new SchemaDefinition();
434                 PropertyDefinition schemeProperty = new PropertyDefinition();
435                 schemeProperty.setType(schemaType);
436                 schema.setProperty(schemeProperty);
437                 result = Either.left(schema);
438
439             } else if (propertyFieldEntryScheme.left().value() instanceof Map) {
440                 PropertyDefinition schemeProperty = createModuleProperty((Map<String, Object>) propertyFieldEntryScheme.left().value());
441                 SchemaDefinition schema = new SchemaDefinition();
442                 schema.setProperty(schemeProperty);
443                 result = Either.left(schema);
444
445             }
446
447         }
448         return result;
449     }
450
451     public static void setField(Map<String, Object> toscaJson, ToscaTagNamesEnum tagName, Consumer<String> setter) {
452         Either<String, ResultStatusEnum> fieldStringValue = findFirstToscaStringElement(toscaJson, tagName);
453         if (fieldStringValue.isLeft()) {
454             setter.accept(fieldStringValue.left().value());
455         }
456
457     }
458
459     private static void setPropertyFieldRequired(Map<String, Object> propertyValue, PropertyDefinition dataDefinition) {
460         Either<String, ResultStatusEnum> propertyFieldRequired = findFirstToscaBooleanElement(propertyValue, ToscaTagNamesEnum.REQUIRED);
461         if (propertyFieldRequired.isLeft()) {
462             dataDefinition.setRequired(Boolean.parseBoolean(propertyFieldRequired.left().value()));
463         }
464     }
465
466     public static Either<Map<String, PropertyDefinition>, ResultStatusEnum> getProperties(Map<String, Object> toscaJson) {
467         Function<String, PropertyDefinition> elementGenByName = elementName -> createProperties(elementName);
468         Function<Map<String, Object>, PropertyDefinition> func = map -> createModuleProperty(map);
469
470         return getElements(toscaJson, ToscaTagNamesEnum.PROPERTIES, elementGenByName, func);
471
472     }
473
474     public static Either<Map<String, InputDefinition>, ResultStatusEnum> getInputs(Map<String, Object> toscaJson) {
475         Function<String, InputDefinition> elementGenByName = elementName -> createInputs(elementName);
476         Function<Map<String, Object>, InputDefinition> func = map -> createModuleInput(map);
477
478         return getElements(toscaJson, ToscaTagNamesEnum.INPUTS, elementGenByName, func);
479
480     }
481
482     public static Either<Map<String, PropertyDefinition>, ResultStatusEnum> getAttributes(Map<String, Object> toscaJson) {
483         Function<String, PropertyDefinition> elementGenByName = elementName -> createAttribute(elementName);
484         Function<Map<String, Object>, PropertyDefinition> func = map -> createModuleAttribute(map);
485
486         return getElements(toscaJson, ToscaTagNamesEnum.ATTRIBUTES, elementGenByName, func);
487     }
488
489     public static <ElementDefinition> Either<Map<String, ElementDefinition>, ResultStatusEnum> getElements(Map<String, Object> toscaJson, ToscaTagNamesEnum elementTagName, Function<String, ElementDefinition> elementGenByName,
490             Function<Map<String, Object>, ElementDefinition> func) {
491         Either<Map<String, ElementDefinition>, ResultStatusEnum> eitherResult = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
492         Either<Map<String, Object>, ResultStatusEnum> toscaAttributes = findFirstToscaMapElement(toscaJson, elementTagName);
493         if (toscaAttributes.isLeft()) {
494             Map<String, Object> jsonAttributes = toscaAttributes.left().value();
495             Map<String, ElementDefinition> moduleAttributes = new HashMap<>();
496             Iterator<Entry<String, Object>> propertiesNameValue = jsonAttributes.entrySet().iterator();
497             while (propertiesNameValue.hasNext()) {
498                 Entry<String, Object> attributeNameValue = propertiesNameValue.next();
499                 if (attributeNameValue.getValue() instanceof Map) {
500                     @SuppressWarnings("unchecked")
501                     ElementDefinition attribute = func.apply((Map<String, Object>) attributeNameValue.getValue());
502                     moduleAttributes.put(String.valueOf(attributeNameValue.getKey()), attribute);
503                 } else {
504
505                     ElementDefinition element = elementGenByName.apply(String.valueOf(attributeNameValue.getValue()));
506
507                     moduleAttributes.put(String.valueOf(attributeNameValue.getKey()), element);
508                 }
509
510             }
511
512             if (moduleAttributes.size() > 0) {
513                 eitherResult = Either.left(moduleAttributes);
514             }
515
516         }
517         return eitherResult;
518
519     }
520
521     private static PropertyDefinition createAttribute(String name) {
522         PropertyDefinition attribute = new PropertyDefinition();
523
524         attribute.setName(name);
525         return attribute;
526     }
527
528     private static PropertyDefinition createProperties(String name) {
529         PropertyDefinition property = new PropertyDefinition();
530         property.setDefaultValue(name);
531         property.setName(name);
532         return property;
533     }
534
535     private static InputDefinition createInputs(String name) {
536         InputDefinition input = new InputDefinition();
537
538         input.setName(name);
539         return input;
540     }
541
542     public static Either<List<HeatParameterDefinition>, ResultStatusEnum> getHeatParameters(Map<String, Object> heatData, String artifactType) {
543
544         Either<List<HeatParameterDefinition>, ResultStatusEnum> eitherResult = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
545         Either<Map<String, Object>, ResultStatusEnum> toscaProperties = findFirstToscaMapElement(heatData, ToscaTagNamesEnum.PARAMETERS);
546         if (toscaProperties.isLeft()) {
547             Map<String, Object> jsonProperties = toscaProperties.left().value();
548             List<HeatParameterDefinition> moduleProperties = new ArrayList<>();
549             Iterator<Entry<String, Object>> propertiesNameValue = jsonProperties.entrySet().iterator();
550             while (propertiesNameValue.hasNext()) {
551                 Entry<String, Object> propertyNameValue = propertiesNameValue.next();
552                 if (propertyNameValue.getValue() instanceof Map || propertyNameValue.getValue() instanceof List) {
553                     if (!artifactType.equals(ArtifactTypeEnum.HEAT_ENV.getType())) {
554                         @SuppressWarnings("unchecked")
555                         Either<HeatParameterDefinition, ResultStatusEnum> propertyStatus = createModuleHeatParameter((Map<String, Object>) propertyNameValue.getValue());
556                         if (propertyStatus.isRight()) {
557                             return Either.right(propertyStatus.right().value());
558                         }
559                         HeatParameterDefinition property = propertyStatus.left().value();
560                         property.setName(String.valueOf(propertyNameValue.getKey()));
561                         moduleProperties.add(property);
562                     } else {
563                         addHeatParamDefinition(moduleProperties, propertyNameValue, true);
564                     }
565                 } else {
566                     addHeatParamDefinition(moduleProperties, propertyNameValue, false);
567                 }
568
569             }
570
571             if (moduleProperties.size() > 0) {
572                 eitherResult = Either.left(moduleProperties);
573             }
574
575         }
576         return eitherResult;
577
578     }
579
580     private static void addHeatParamDefinition(List<HeatParameterDefinition> moduleProperties, Entry<String, Object> propertyNameValue, boolean isJson) {
581         HeatParameterDefinition property = new HeatParameterDefinition();
582         Object value = propertyNameValue.getValue();
583         if (value != null) {
584             property.setDefaultValue(isJson ? new Gson().toJson(value).toString() : StringEscapeUtils.escapeJava(String.valueOf(value)));
585         }
586         property.setName(String.valueOf(propertyNameValue.getKey()));
587         moduleProperties.add(property);
588     }
589
590     private static Either<HeatParameterDefinition, ResultStatusEnum> createModuleHeatParameter(Map<String, Object> propertyValue) {
591         HeatParameterDefinition propertyDef = new HeatParameterDefinition();
592         String type;
593         Either<String, ResultStatusEnum> propertyFieldType = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.TYPE);
594         if (propertyFieldType.isLeft()) {
595             type = propertyFieldType.left().value();
596             propertyDef.setType(type);
597         } else {
598             return Either.right(ResultStatusEnum.INVALID_PROPERTY_TYPE);
599         }
600         Either<String, ResultStatusEnum> propertyFieldDescription = findFirstToscaStringElement(propertyValue, ToscaTagNamesEnum.DESCRIPTION);
601         if (propertyFieldDescription.isLeft()) {
602             propertyDef.setDescription(propertyFieldDescription.left().value());
603         }
604
605         Either<Object, ResultStatusEnum> propertyFieldDefaultVal = findToscaElement(propertyValue, ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL);
606         if (propertyFieldDefaultVal.isLeft()) {
607             if (propertyFieldDefaultVal.left().value() == null) {
608                 return Either.right(ResultStatusEnum.INVALID_PROPERTY_VALUE);
609             }
610             Object value = propertyFieldDefaultVal.left().value();
611             String defaultValue = type.equals(HeatParameterType.JSON.getType()) ? new Gson().toJson(value).toString() : StringEscapeUtils.escapeJava(String.valueOf(value));
612             propertyDef.setDefaultValue(defaultValue);
613             propertyDef.setCurrentValue(defaultValue);
614         }
615
616         return Either.left(propertyDef);
617     }
618
619     public static String getPropertyJsonStringValue(Object value, String type) {
620         Gson gson = new Gson();
621         if (type == null) {
622             return null;
623         }
624         ToscaPropertyType validType = ToscaPropertyType.isValidType(type);
625         if (validType == null ||  validType.equals(ToscaPropertyType.JSON) ||validType.equals(ToscaPropertyType.MAP) || validType.equals(ToscaPropertyType.LIST)) {
626             return gson.toJson(value);
627         }
628         return value.toString();
629     }
630
631     /**
632      * removes from Json map (toscaJson) first element found by name (elementName) note that this method could update the received argument toscaJson
633      *
634      * @param toscaJson
635      * @param elementName
636      */
637     public static void removeElementFromJsonMap(Map<String, Object> toscaJson, String elementName) {
638         for (Entry<String, Object> entry : toscaJson.entrySet()) {
639             String key = entry.getKey();
640             Object value = entry.getValue();
641             if (key.equals(elementName)) {
642                 toscaJson.remove(elementName);
643                 return;
644             } else if (value instanceof Map) {
645                 removeElementFromJsonMap((Map<String, Object>) value, elementName);
646             }
647         }
648     }
649 }