cc6b359098196e4b8aec67e95734a57a12bdf76b
[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.JsonParseException;
26 import com.google.gson.reflect.TypeToken;
27 import fj.data.Either;
28 import org.apache.commons.collections.CollectionUtils;
29 import org.apache.commons.lang3.StringEscapeUtils;
30 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
31 import org.openecomp.sdc.be.config.BeEcompErrorManager;
32 import org.openecomp.sdc.be.dao.api.ActionStatus;
33 import org.openecomp.sdc.be.datatypes.elements.Annotation;
34 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
35 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
36 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
37 import org.openecomp.sdc.be.impl.ComponentsUtils;
38 import org.openecomp.sdc.be.model.AnnotationTypeDefinition;
39 import org.openecomp.sdc.be.model.HeatParameterDefinition;
40 import org.openecomp.sdc.be.model.InputDefinition;
41 import org.openecomp.sdc.be.model.LifecycleStateEnum;
42 import org.openecomp.sdc.be.model.PropertyConstraint;
43 import org.openecomp.sdc.be.model.PropertyDefinition;
44 import org.openecomp.sdc.be.model.heat.HeatParameterType;
45 import org.openecomp.sdc.be.model.operations.impl.AnnotationTypeOperations;
46 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation.PropertyConstraintDeserialiser;
47 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
48 import org.openecomp.sdc.be.model.tosca.constraints.ConstraintType;
49 import org.openecomp.sdc.be.model.tosca.constraints.ValidValuesConstraint;
50 import org.openecomp.sdc.be.model.tosca.constraints.exception.ConstraintValueDoNotMatchPropertyTypeException;
51 import org.openecomp.sdc.be.utils.TypeUtils;
52 import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum;
53 import org.openecomp.sdc.common.api.ArtifactTypeEnum;
54 import org.openecomp.sdc.common.log.wrappers.Logger;
55 import org.openecomp.sdc.exception.ResponseFormat;
56 import org.springframework.beans.factory.annotation.Autowired;
57 import org.springframework.beans.factory.config.YamlProcessor;
58 import org.springframework.stereotype.Component;
59 import org.yaml.snakeyaml.DumperOptions;
60 import org.yaml.snakeyaml.Yaml;
61 import org.yaml.snakeyaml.constructor.Constructor;
62 import org.yaml.snakeyaml.nodes.Tag;
63 import org.yaml.snakeyaml.representer.Representer;
64 import org.yaml.snakeyaml.resolver.Resolver;
65
66 import java.lang.reflect.Type;
67 import java.util.ArrayList;
68 import java.util.Collection;
69 import java.util.Collections;
70 import java.util.HashMap;
71 import java.util.Iterator;
72 import java.util.LinkedHashMap;
73 import java.util.List;
74 import java.util.Map;
75 import java.util.Map.Entry;
76 import java.util.function.Consumer;
77 import java.util.function.Function;
78
79 import static org.apache.commons.collections.CollectionUtils.isEmpty;
80 import static org.openecomp.sdc.be.components.impl.ResourceImportManager.PROPERTY_NAME_PATTERN_IGNORE_LENGTH;
81 import static org.openecomp.sdc.be.datatypes.elements.Annotation.setAnnotationsName;
82
83 @Component
84 public final class ImportUtils {
85
86     private static final CustomResolver customResolver = new CustomResolver();
87     private static final Yaml strictYamlLoader =  new YamlLoader().getStrictYamlLoader();
88
89     protected static ComponentsUtils componentsUtils;
90
91     private static final Logger log = Logger.getLogger(ImportUtils.class);
92
93     private ImportUtils() {
94     }
95
96     @Autowired
97     public static void setComponentsUtils(ComponentsUtils componentsUtils) {
98         ImportUtils.componentsUtils = componentsUtils;
99     }
100
101     private static class CustomResolver extends Resolver {
102         @Override
103         protected void addImplicitResolvers() {
104             // avoid implicit resolvers for strings that can be interpreted as boolean values
105             addImplicitResolver(Tag.STR, EMPTY, "");
106             addImplicitResolver(Tag.STR, NULL, null);
107             addImplicitResolver(Tag.NULL, NULL, "~nN\0");
108             addImplicitResolver(Tag.NULL, EMPTY, null);
109             addImplicitResolver(Tag.INT, INT, "-+0123456789");
110             addImplicitResolver(Tag.FLOAT, FLOAT, "-+0123456789.");
111             addImplicitResolver(Tag.YAML, YAML, "!&*");
112         }
113     }
114
115
116     private static void buildMap(Map<String, Object> output, Map<String, Object> map) {
117         for (Entry<String, Object> entry : map.entrySet()) {
118             String key = entry.getKey();
119             Object value = entry.getValue();
120             if (value instanceof Map) {
121                 Map<String, Object> result = new LinkedHashMap<>();
122                 buildMap(result, (Map) value);
123                 output.put(key, result);
124             }
125             else if (value instanceof Collection) {
126                 Map<String, Object> result = new LinkedHashMap<>();
127                 int i = 0;
128                 for(Object item : (Collection<Object>) value) {
129                     buildMap(result, Collections.singletonMap("[" + (i++) + "]", item));
130                 }
131                 output.put(key, new ArrayList<>(result.values()));
132             }
133             else {
134                 output.put(key, value);
135             }
136         }
137     }
138
139     public static Map<String, Object> loadYamlAsStrictMap(String content){
140         Map<String, Object> result = new LinkedHashMap<>();
141         Object map = strictYamlLoader.load(content);
142         buildMap(result, (Map<String, Object>)map);
143         return result;
144     }
145
146     private static class YamlLoader extends YamlProcessor {
147         public Yaml getStrictYamlLoader() {
148             return createYaml();
149         }
150     }
151
152     @SuppressWarnings("unchecked")
153     public static Either<List<HeatParameterDefinition>, ResultStatusEnum> getHeatParamsWithoutImplicitTypes(String heatDecodedPayload, String artifactType) {
154         Map<String, Object> heatData = (Map<String, Object>) new Yaml(new Constructor(), new Representer(), new DumperOptions(), customResolver).load(heatDecodedPayload);
155         return getHeatParameters(heatData, artifactType);
156     }
157
158     public static class Constants {
159         public static final String FIRST_NON_CERTIFIED_VERSION = "0.1";
160         public static final String VENDOR_NAME = "ONAP (Tosca)";
161         public static final String VENDOR_RELEASE = "1.0.0.wd03";
162         public static final LifecycleStateEnum NORMATIVE_TYPE_LIFE_CYCLE = LifecycleStateEnum.CERTIFIED;
163         public static final LifecycleStateEnum NORMATIVE_TYPE_LIFE_CYCLE_NOT_CERTIFIED_CHECKOUT = LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT;
164         public static final boolean NORMATIVE_TYPE_HIGHEST_VERSION = true;
165         public static final String ABSTRACT_CATEGORY_NAME = "Generic";
166         public static final String ABSTRACT_SUBCATEGORY = "Abstract";
167         public static final String DEFAULT_ICON = "defaulticon";
168         public static final String INNER_VFC_DESCRIPTION = "Not reusable inner VFC";
169         public static final String USER_DEFINED_RESOURCE_NAMESPACE_PREFIX = "org.openecomp.resource.";
170         public static final String UI_JSON_PAYLOAD_NAME = "payloadName";
171         public static final String CVFC_DESCRIPTION = "Complex node type that is used as nested type in VF";
172         public static final String ESCAPED_DOUBLE_QUOTE = "\"";
173         public static final String QUOTE = "'";
174
175         private Constants() {}
176     }
177
178     public enum ResultStatusEnum {
179         ELEMENT_NOT_FOUND, GENERAL_ERROR, OK, INVALID_PROPERTY_DEFAULT_VALUE, INVALID_PROPERTY_TYPE, INVALID_PROPERTY_VALUE, MISSING_ENTRY_SCHEMA_TYPE, INVALID_PROPERTY_NAME
180     }
181
182     public enum ToscaElementTypeEnum {
183         BOOLEAN, STRING, MAP, LIST, ALL
184     }
185
186     @SuppressWarnings("unchecked")
187     private static void handleElementNameNotFound(String elementName, Object elementValue, ToscaElementTypeEnum elementType, List<Object> returnedList) {
188         if (elementValue instanceof Map) {
189             ImportUtils.findToscaElements((Map<String, Object>) elementValue, elementName, elementType, returnedList);
190         } else if (elementValue instanceof List) {
191             ImportUtils.findAllToscaElementsInList((List<Object>) elementValue, elementName, elementType, returnedList);
192         }
193     }
194
195     @SuppressWarnings("unchecked")
196     private static void addFoundElementAccordingToItsType(String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList, Object elementValue) {
197
198         if (elementValue instanceof Boolean) {
199             if (elementType == ToscaElementTypeEnum.BOOLEAN || elementType == ToscaElementTypeEnum.ALL) {
200                 returnedList.add(elementValue);
201             }
202         }
203
204         else if (elementValue instanceof String) {
205             if (elementType == ToscaElementTypeEnum.STRING || elementType == ToscaElementTypeEnum.ALL) {
206                 returnedList.add(elementValue);
207             }
208         } else if (elementValue instanceof Map) {
209             if (elementType == ToscaElementTypeEnum.MAP || elementType == ToscaElementTypeEnum.ALL) {
210                 returnedList.add(elementValue);
211             }
212             ImportUtils.findToscaElements((Map<String, Object>) elementValue, elementName, elementType, returnedList);
213
214         } else if (elementValue instanceof List) {
215             if (elementType == ToscaElementTypeEnum.LIST || elementType == ToscaElementTypeEnum.ALL) {
216                 returnedList.add(elementValue);
217             }
218             ImportUtils.findAllToscaElementsInList((List<Object>) elementValue, elementName, elementType, returnedList);
219
220         }
221         // For Integer, Double etc...
222         else if (elementType == ToscaElementTypeEnum.ALL && elementValue != null) {
223             returnedList.add(String.valueOf(elementValue));
224         }
225     }
226
227     private static void findAllToscaElementsInList(List<Object> list, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) {
228         list.forEach(elementValue -> handleElementNameNotFound(elementName, elementValue, elementType, returnedList));
229     }
230
231     public static Either<Object, ResultStatusEnum> findToscaElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum elementName, ToscaElementTypeEnum elementType) {
232         List<Object> foundElements = new ArrayList<>();
233         ImportUtils.findToscaElements(toscaJson, elementName.getElementName(), elementType, foundElements);
234         if (!isEmpty(foundElements)) {
235             return Either.left(foundElements.get(0));
236         }
237         return Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
238     }
239
240     /**
241      * Recursively searches for all tosca elements with key equals to elementName and value equals to elementType. <br>
242      * Returns Either element with:<br>
243      * List with all value if values found<br>
244      * Or ELEMENT_NOT_FOUND ActionStatus
245      *
246      * @param toscaJson
247      * @return
248      */
249     public static Either<List<Object>, ResultStatusEnum> findToscaElements(Map<String, Object> toscaJson, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) {
250         Either<List<Object>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
251         String skipKey = null;
252         if (toscaJson.containsKey(elementName)) {
253             skipKey = handleFoundElement(toscaJson, elementName, elementType, returnedList);
254         }
255
256
257         Iterator<Entry<String, Object>> keyValItr = toscaJson.entrySet().iterator();
258         while (keyValItr.hasNext()) {
259             Entry<String, Object> keyValEntry = keyValItr.next();
260             if (!String.valueOf(keyValEntry.getKey()).equals(skipKey)) {
261                 handleElementNameNotFound(elementName, keyValEntry.getValue(), elementType, returnedList);
262             }
263         }
264
265         if (!isEmpty(returnedList)) {
266             returnedElement = Either.left(returnedList);
267         }
268
269         return returnedElement;
270     }
271
272     private static String handleFoundElement(Map<String, Object> toscaJson, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) {
273         Object elementValue = toscaJson.get(elementName);
274         addFoundElementAccordingToItsType(elementName, elementType, returnedList, elementValue);
275         return elementName;
276
277     }
278
279     @SuppressWarnings("unchecked")
280     public static <T> Either<List<T>, ResultStatusEnum> findFirstToscaListElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum toscaTagName) {
281         Either<List<T>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
282         Either<Object, ResultStatusEnum> findFirstToscaElement = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.LIST);
283         if (findFirstToscaElement.isLeft()) {
284             returnedElement = Either.left((List<T>) findFirstToscaElement.left().value());
285         }
286         return returnedElement;
287
288     }
289
290     @SuppressWarnings("unchecked")
291     public static <T> Either<Map<String, T>, ResultStatusEnum> findFirstToscaMapElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum toscaTagName) {
292         Either<Map<String, T>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
293         Either<Object, ResultStatusEnum> findFirstToscaElement = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.MAP);
294         if (findFirstToscaElement.isLeft()) {
295             returnedElement = Either.left((Map<String, T>) findFirstToscaElement.left().value());
296         }
297         return returnedElement;
298
299     }
300
301     public static Either<String, ResultStatusEnum> findFirstToscaStringElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum toscaTagName) {
302         Either<String, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
303         Either<Object, ResultStatusEnum> findFirstToscaElements = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.STRING);
304         if (findFirstToscaElements.isLeft()) {
305             returnedElement = Either.left((String) findFirstToscaElements.left().value());
306         }
307         return returnedElement;
308     }
309
310     /**
311      * searches for first Tosca in Json map (toscaJson) boolean element by name (toscaTagName) returns found element or ELEMENT_NOT_FOUND status
312      *
313      * @param toscaJson
314      * @param toscaTagName
315      * @return
316      */
317     public static Either<String, ResultStatusEnum> findFirstToscaBooleanElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum toscaTagName) {
318         Either<String, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
319         Either<Object, ResultStatusEnum> findFirstToscaElements = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.BOOLEAN);
320         if (findFirstToscaElements.isLeft()) {
321             returnedElement = Either.left(String.valueOf(findFirstToscaElements.left().value()));
322         }
323         return returnedElement;
324     }
325
326     private static void setPropertyConstraints(Map<String, Object> propertyValue, PropertyDefinition property) {
327         List<PropertyConstraint> constraints = getPropertyConstraints(propertyValue, property.getType());
328         if (CollectionUtils.isNotEmpty(constraints)) {
329             property.setConstraints(constraints);
330         }
331     }
332
333     private static List<PropertyConstraint> getPropertyConstraints(Map<String, Object> propertyValue, String propertyType) {
334         List<Object> propertyFieldConstraints = findCurrentLevelConstraintsElement(propertyValue);
335         if (CollectionUtils.isNotEmpty(propertyFieldConstraints)) {
336             List<PropertyConstraint> constraintList = new ArrayList<>();
337             Type constraintType = new TypeToken<PropertyConstraint>() {
338             }.getType();
339             Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create();
340
341             for (Object constraintJson : propertyFieldConstraints) {
342                 PropertyConstraint propertyConstraint = validateAndGetPropertyConstraint(propertyType, constraintType, gson, constraintJson);
343                 constraintList.add(propertyConstraint);
344             }
345             return constraintList;
346         }
347         return null;
348     }
349
350     private static List<Object> findCurrentLevelConstraintsElement(Map<String, Object> toscaJson) {
351         List<Object> constraints = null;
352         if (toscaJson.containsKey(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName())) {
353             try {
354                 constraints = (List<Object>) toscaJson.get(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName());
355             } catch (ClassCastException e){
356                 throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY_CONSTRAINTS_FORMAT, toscaJson.get(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName()).toString());
357             }
358         }
359         return constraints;
360
361     }
362
363     private static PropertyConstraint validateAndGetPropertyConstraint(String propertyType, Type constraintType, Gson gson, Object constraintJson) {
364         PropertyConstraint propertyConstraint;
365         try{
366             propertyConstraint = gson.fromJson(gson.toJson(constraintJson), constraintType);
367         } catch (ClassCastException|JsonParseException e){
368             throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY_CONSTRAINTS_FORMAT, constraintJson.toString());
369         }
370         if(propertyConstraint!= null && propertyConstraint instanceof ValidValuesConstraint){
371             try {
372                 ((ValidValuesConstraint)propertyConstraint).validateType(propertyType);
373             } catch (ConstraintValueDoNotMatchPropertyTypeException e) {
374                 BeEcompErrorManager.getInstance().logInternalFlowError("GetInitializedPropertyConstraint",
375                         e.getMessage(), BeEcompErrorManager.ErrorSeverity.ERROR);
376                 throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY_CONSTRAINTS, ConstraintType.VALID_VALUES.name(),
377                         ((ValidValuesConstraint) propertyConstraint).getValidValues().toString(), propertyType);
378             }
379         }
380         return propertyConstraint;
381     }
382
383     public static PropertyDefinition createModuleProperty(Map<String, Object> propertyValue) {
384
385         PropertyDefinition propertyDef = new PropertyDefinition();
386         setField(propertyValue, TypeUtils.ToscaTagNamesEnum.TYPE, propertyDef::setType);
387         setFieldBoolean(propertyValue, ToscaTagNamesEnum.REQUIRED, req -> propertyDef.setRequired(Boolean.parseBoolean(req)));
388         setField(propertyValue, TypeUtils.ToscaTagNamesEnum.DESCRIPTION, propertyDef::setDescription);
389
390         setJsonStringField(propertyValue, TypeUtils.ToscaTagNamesEnum.DEFAULT_VALUE, propertyDef.getType(), propertyDef::setDefaultValue);
391         setJsonStringField(propertyValue, TypeUtils.ToscaTagNamesEnum.VALUE, propertyDef.getType(), propertyDef::setValue);
392
393         setFieldBoolean(propertyValue, TypeUtils.ToscaTagNamesEnum.IS_PASSWORD, pass -> propertyDef.setPassword(Boolean.parseBoolean(pass)));
394         setField(propertyValue, TypeUtils.ToscaTagNamesEnum.STATUS, propertyDef::setStatus);
395         setScheme(propertyValue, propertyDef);
396         setPropertyConstraints(propertyValue, propertyDef);
397
398         return propertyDef;
399     }
400
401
402     private static void setJsonStringField(Map<String, Object> propertyValue, ToscaTagNamesEnum elementName, String type, Consumer<String> setter) {
403         Either<Object, ResultStatusEnum> eitherValue = ImportUtils.findToscaElement(propertyValue, elementName, ToscaElementTypeEnum.ALL);
404         if (eitherValue.isLeft()) {
405             String propertyJsonStringValue = getPropertyJsonStringValue(eitherValue.left().value(), type);
406             setter.accept(propertyJsonStringValue);
407         }
408     }
409
410
411
412     public static Annotation createModuleAnnotation(Map<String, Object> annotationMap, AnnotationTypeOperations annotationTypeOperations) {
413         String parsedAnnotationType = findFirstToscaStringElement(annotationMap, TypeUtils.ToscaTagNamesEnum.TYPE).left().value();
414         AnnotationTypeDefinition annotationTypeObject = annotationTypeOperations.getLatestType(parsedAnnotationType);
415         if (annotationTypeObject != null) {
416             Annotation annotation = new Annotation();
417             ImportUtils.setField(annotationMap, TypeUtils.ToscaTagNamesEnum.TYPE, annotation::setType);
418             ImportUtils.setField(annotationMap, TypeUtils.ToscaTagNamesEnum.DESCRIPTION, annotation::setDescription);
419             Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = getProperties(annotationMap);
420             modifyPropertiesKeysToProperForm(properties, annotation);
421             return annotation;
422         }
423         return null;
424     }
425
426     private static Either<Boolean, ResponseFormat> modifyPropertiesKeysToProperForm(Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties, Annotation annotation) {
427         Either<Boolean, ResponseFormat> result = Either.left(true);
428         if (properties.isLeft()) {
429             List<PropertyDataDefinition> propertiesList = new ArrayList<>();
430             Map<String, PropertyDefinition> value = properties.left().value();
431             if (value != null) {
432                 for (Entry<String, PropertyDefinition> entry : value.entrySet()) {
433                     String name = entry.getKey();
434                     if (!PROPERTY_NAME_PATTERN_IGNORE_LENGTH.matcher(name).matches()) {
435                         log.debug("The property with invalid name {} occurred upon import resource {}. ", name, annotation.getName());
436                         result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromResultStatusEnum(ResultStatusEnum.INVALID_PROPERTY_NAME, JsonPresentationFields.PROPERTY)));
437                     }
438                     PropertyDefinition propertyDefinition = entry.getValue();
439                     propertyDefinition.setValue(propertyDefinition.getName());
440                     propertyDefinition.setName(name);
441                     propertiesList.add(propertyDefinition);
442                 }
443             }
444             annotation.setProperties(propertiesList);
445         }
446         else if (properties.right().value() != ResultStatusEnum.ELEMENT_NOT_FOUND) {
447             result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromResultStatusEnum(properties
448                     .right()
449                     .value(), JsonPresentationFields.PROPERTY)));
450         }
451         return result;
452     }
453
454     public static InputDefinition createModuleInput(Map<String, Object> inputValue, AnnotationTypeOperations annotationTypeOperations) {
455
456         InputDefinition inputDef = new InputDefinition();
457         ImportUtils.setField(inputValue, TypeUtils.ToscaTagNamesEnum.TYPE, inputDef::setType);
458         ImportUtils.setFieldBoolean(inputValue, ToscaTagNamesEnum.REQUIRED, req -> inputDef.setRequired(Boolean.parseBoolean(req)));
459         ImportUtils.setField(inputValue, TypeUtils.ToscaTagNamesEnum.DESCRIPTION, inputDef::setDescription);
460
461         setJsonStringField(inputValue, TypeUtils.ToscaTagNamesEnum.DEFAULT_VALUE, inputDef.getType(), inputDef::setDefaultValue);
462
463         ImportUtils.setFieldBoolean(inputValue, TypeUtils.ToscaTagNamesEnum.IS_PASSWORD, pass -> inputDef.setPassword(Boolean.parseBoolean(pass)));
464         ImportUtils.setField(inputValue, TypeUtils.ToscaTagNamesEnum.STATUS, inputDef::setStatus);
465         ImportUtils.setField(inputValue, TypeUtils.ToscaTagNamesEnum.LABEL, inputDef::setLabel);
466         ImportUtils.setFieldBoolean(inputValue, TypeUtils.ToscaTagNamesEnum.HIDDEN, hidden -> inputDef.setHidden(Boolean.parseBoolean(hidden)));
467         ImportUtils.setFieldBoolean(inputValue, TypeUtils.ToscaTagNamesEnum.IMMUTABLE, immutable -> inputDef.setImmutable(Boolean.parseBoolean(immutable)));
468
469         ImportUtils.setScheme(inputValue, inputDef);
470         ImportUtils.setPropertyConstraints(inputValue, inputDef);
471
472         return parseAnnotationsAndAddItToInput(inputDef, inputValue, annotationTypeOperations);
473
474     }
475
476
477     public static InputDefinition parseAnnotationsAndAddItToInput(InputDefinition inputDef, Map<String, Object> inputValue, AnnotationTypeOperations annotationTypeOperations){
478         Function<String, Annotation> elementGenByName = ImportUtils::createAnnotation;
479         Function<Map<String, Object>, Annotation> func = annotation -> createModuleAnnotation(annotation, annotationTypeOperations);
480         return getElements(inputValue, TypeUtils.ToscaTagNamesEnum.ANNOTATIONS, elementGenByName, func).
481                 left().map( annotations -> modifyInputWithAnnotations(inputDef, annotations)).
482                 left().on(err -> { log.error("Parsing annotations or adding them to the PropertyDataDefinition object failed");
483                                     return inputDef;});
484     }
485
486     private static InputDefinition modifyInputWithAnnotations(InputDefinition inputDef, Map<String, Annotation> annotationsMap) {
487         setAnnotationsName(annotationsMap);
488         inputDef.setAnnotationsToInput(annotationsMap.values());
489         return inputDef;
490     }
491
492
493     public static PropertyDefinition createModuleAttribute(Map<String, Object> attributeMap) {
494
495         PropertyDefinition attributeDef = new PropertyDefinition();
496         setField(attributeMap, TypeUtils.ToscaTagNamesEnum.TYPE, attributeDef::setType);
497         setField(attributeMap, TypeUtils.ToscaTagNamesEnum.DESCRIPTION, attributeDef::setDescription);
498         setField(attributeMap, TypeUtils.ToscaTagNamesEnum.STATUS, attributeDef::setStatus);
499
500         setJsonStringField(attributeMap, TypeUtils.ToscaTagNamesEnum.DEFAULT_VALUE, attributeDef.getType(), attributeDef::setDefaultValue);
501         setJsonStringField(attributeMap, TypeUtils.ToscaTagNamesEnum.VALUE, attributeDef.getType(), attributeDef::setValue);
502
503         setScheme(attributeMap, attributeDef);
504         return attributeDef;
505     }
506
507     private static void setScheme(Map<String, Object> propertyValue, PropertyDefinition propertyDefinition) {
508         Either<Object, ResultStatusEnum> schemaElementRes = findSchemaElement(propertyValue);
509         if (schemaElementRes.isLeft()) {
510             SchemaDefinition schemaDef = getSchema(schemaElementRes.left().value());
511             propertyDefinition.setSchema(schemaDef);
512         }
513     }
514
515     private static Either<Object,ResultStatusEnum> findSchemaElement(Map<String, Object> propertyValue) {
516         return findToscaElement(propertyValue, TypeUtils.ToscaTagNamesEnum.ENTRY_SCHEMA, ToscaElementTypeEnum.ALL);
517     }
518
519     private static SchemaDefinition getSchema(Object propertyFieldEntryScheme) {
520         SchemaDefinition schema = new SchemaDefinition();
521         if (propertyFieldEntryScheme instanceof String) {
522             String schemaType = (String) propertyFieldEntryScheme;
523             PropertyDefinition schemeProperty = new PropertyDefinition();
524             schemeProperty.setType(schemaType);
525             schema.setProperty(schemeProperty);
526         } else if (propertyFieldEntryScheme instanceof Map) {
527             PropertyDefinition schemeProperty = createModuleProperty((Map<String, Object>) propertyFieldEntryScheme);
528             schema.setProperty(schemeProperty);
529         }
530         return schema;
531     }
532
533     public static void setField(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum tagName, Consumer<String> setter) {
534         Either<String, ResultStatusEnum> fieldStringValue = findFirstToscaStringElement(toscaJson, tagName);
535         if (fieldStringValue.isLeft()) {
536             setter.accept(fieldStringValue.left().value());
537         }
538
539     }
540
541     public static void setFieldBoolean(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum tagName, Consumer<String> setter) {
542         Either<String, ResultStatusEnum> fieldStringValue = findFirstToscaBooleanElement(toscaJson, tagName);
543         if (fieldStringValue.isLeft()) {
544             setter.accept(fieldStringValue.left().value());
545         }
546
547     }
548
549
550     public static Either<Map<String, PropertyDefinition>, ResultStatusEnum> getProperties(Map<String, Object> toscaJson) {
551         Function<String, PropertyDefinition> elementGenByName = ImportUtils::createProperties;
552         Function<Map<String, Object>, PropertyDefinition> func = ImportUtils::createModuleProperty;
553
554         return getElements(toscaJson, TypeUtils.ToscaTagNamesEnum.PROPERTIES, elementGenByName, func);
555
556     }
557
558     public static Either<Map<String, InputDefinition>, ResultStatusEnum> getInputs(Map<String, Object> toscaJson, AnnotationTypeOperations annotationTypeOperations) {
559         Function<String, InputDefinition> elementGenByName = ImportUtils::createInputs;
560         Function<Map<String, Object>, InputDefinition> func = object -> createModuleInput(object, annotationTypeOperations);
561
562         return getElements(toscaJson, TypeUtils.ToscaTagNamesEnum.INPUTS, elementGenByName, func);
563
564     }
565
566     public static Either<Map<String, PropertyDefinition>, ResultStatusEnum> getAttributes(Map<String, Object> toscaJson) {
567         Function<String, PropertyDefinition> elementGenByName = ImportUtils::createAttribute;
568         Function<Map<String, Object>, PropertyDefinition> func = ImportUtils::createModuleAttribute;
569
570         return getElements(toscaJson, TypeUtils.ToscaTagNamesEnum.ATTRIBUTES, elementGenByName, func);
571     }
572
573     public static <T> Either<Map<String, T>, ResultStatusEnum>  getElements(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum elementTagName, Function<String, T> elementGenByName,
574                                                                            Function<Map<String, Object>, T> func) {
575         Either<Map<String, T>, ResultStatusEnum> eitherResult = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
576         Either<Map<String, Object>, ResultStatusEnum> toscaAttributes = findFirstToscaMapElement(toscaJson, elementTagName);
577         if (toscaAttributes.isLeft()) {
578             Map<String, Object> jsonAttributes = toscaAttributes.left().value();
579             Map<String, T> moduleAttributes = new HashMap<>();
580             Iterator<Entry<String, Object>> propertiesNameValue = jsonAttributes.entrySet().iterator();
581             while (propertiesNameValue.hasNext()) {
582                 Entry<String, Object> attributeNameValue = propertiesNameValue.next();
583                 if (attributeNameValue.getValue() instanceof Map) {
584                     @SuppressWarnings("unchecked")
585                     T attribute = func.apply((Map<String, Object>) attributeNameValue.getValue());
586                     if (attribute != null){
587                         moduleAttributes.put(String.valueOf(attributeNameValue.getKey()), attribute);
588                     }
589                 }
590                 else {
591                     T element = elementGenByName.apply(String.valueOf(attributeNameValue.getValue()));
592                     moduleAttributes.put(String.valueOf(attributeNameValue.getKey()), element);
593                 }
594             }
595             if (moduleAttributes.size() > 0) {
596                 eitherResult = Either.left(moduleAttributes);
597             }
598
599         }
600         return eitherResult;
601
602     }
603
604     private static PropertyDefinition createAttribute(String name) {
605         PropertyDefinition attribute = new PropertyDefinition();
606
607         attribute.setName(name);
608         return attribute;
609     }
610
611     private static PropertyDefinition createProperties(String name) {
612         PropertyDefinition property = new PropertyDefinition();
613         property.setDefaultValue(name);
614         property.setName(name);
615         return property;
616     }
617
618
619
620     private static InputDefinition createInputs(String name) {
621         InputDefinition input = new InputDefinition();
622
623         input.setName(name);
624         return input;
625     }
626
627     private static Annotation createAnnotation(String name) {
628         Annotation annotation = new Annotation();
629         annotation.setName(name);
630         return annotation;
631     }
632
633
634
635     public static Either<List<HeatParameterDefinition>, ResultStatusEnum> getHeatParameters(Map<String, Object> heatData, String artifactType) {
636
637         Either<List<HeatParameterDefinition>, ResultStatusEnum> eitherResult = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
638         Either<Map<String, Object>, ResultStatusEnum> toscaProperties = findFirstToscaMapElement(heatData, TypeUtils.ToscaTagNamesEnum.PARAMETERS);
639         if (toscaProperties.isLeft()) {
640             Map<String, Object> jsonProperties = toscaProperties.left().value();
641             List<HeatParameterDefinition> moduleProperties = new ArrayList<>();
642             Iterator<Entry<String, Object>> propertiesNameValue = jsonProperties.entrySet().iterator();
643             while (propertiesNameValue.hasNext()) {
644                 Entry<String, Object> propertyNameValue = propertiesNameValue.next();
645                 if (propertyNameValue.getValue() instanceof Map || propertyNameValue.getValue() instanceof List) {
646                     if (!artifactType.equals(ArtifactTypeEnum.HEAT_ENV.getType())) {
647                         @SuppressWarnings("unchecked")
648                         Either<HeatParameterDefinition, ResultStatusEnum> propertyStatus = createModuleHeatParameter((Map<String, Object>) propertyNameValue.getValue());
649                         if (propertyStatus.isRight()) {
650                             return Either.right(propertyStatus.right().value());
651                         }
652                         HeatParameterDefinition property = propertyStatus.left().value();
653                         property.setName(String.valueOf(propertyNameValue.getKey()));
654                         moduleProperties.add(property);
655                     } else {
656                         addHeatParamDefinition(moduleProperties, propertyNameValue, true);
657                     }
658                 } else {
659                     addHeatParamDefinition(moduleProperties, propertyNameValue, false);
660                 }
661
662             }
663
664             if (!isEmpty(moduleProperties)) {
665                 eitherResult = Either.left(moduleProperties);
666             }
667
668         }
669         return eitherResult;
670
671     }
672
673     private static void addHeatParamDefinition(List<HeatParameterDefinition> moduleProperties, Entry<String, Object> propertyNameValue, boolean isJson) {
674         HeatParameterDefinition property = new HeatParameterDefinition();
675         Object value = propertyNameValue.getValue();
676         if (value != null) {
677             property.setDefaultValue(isJson ? new Gson().toJson(value) : StringEscapeUtils.escapeJava(String.valueOf(value)));
678         }
679         property.setName(String.valueOf(propertyNameValue.getKey()));
680         moduleProperties.add(property);
681     }
682
683     private static Either<HeatParameterDefinition, ResultStatusEnum> createModuleHeatParameter(Map<String, Object> propertyValue) {
684         HeatParameterDefinition propertyDef = new HeatParameterDefinition();
685         String type;
686         Either<String, ResultStatusEnum> propertyFieldType = findFirstToscaStringElement(propertyValue, TypeUtils.ToscaTagNamesEnum.TYPE);
687         if (propertyFieldType.isLeft()) {
688             type = propertyFieldType.left().value();
689             propertyDef.setType(type);
690         } else {
691             return Either.right(ResultStatusEnum.INVALID_PROPERTY_TYPE);
692         }
693         Either<String, ResultStatusEnum> propertyFieldDescription = findFirstToscaStringElement(propertyValue, TypeUtils.ToscaTagNamesEnum.DESCRIPTION);
694         if (propertyFieldDescription.isLeft()) {
695             propertyDef.setDescription(propertyFieldDescription.left().value());
696         }
697
698         Either<Object, ResultStatusEnum> propertyFieldDefaultVal = findToscaElement(propertyValue, TypeUtils.ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL);
699         if (propertyFieldDefaultVal.isLeft()) {
700             if (propertyFieldDefaultVal.left().value() == null) {
701                 return Either.right(ResultStatusEnum.INVALID_PROPERTY_VALUE);
702             }
703             Object value = propertyFieldDefaultVal.left().value();
704             String defaultValue = type.equals(HeatParameterType.JSON.getType()) ? new Gson().toJson(value) : StringEscapeUtils.escapeJava(String.valueOf(value));
705             propertyDef.setDefaultValue(defaultValue);
706             propertyDef.setCurrentValue(defaultValue);
707         }
708
709         return Either.left(propertyDef);
710     }
711     public static boolean containsGetInput(Object propValue) {
712         String value = getPropertyJsonStringValue(propValue, ToscaPropertyType.MAP.getType());
713         return value != null && value.contains(TypeUtils.ToscaTagNamesEnum.GET_INPUT.getElementName());
714     }
715
716     public static String getPropertyJsonStringValue(Object value, String type) {
717         Gson gson = new Gson();
718         if (type == null) {
719             return null;
720         }
721         ToscaPropertyType validType = ToscaPropertyType.isValidType(type);
722         if (validType == null ||  validType == ToscaPropertyType.JSON || validType == ToscaPropertyType.MAP || validType == ToscaPropertyType.LIST) {
723             return gson.toJson(value);
724         }
725         return value.toString();
726     }
727
728     /**
729      * removes from Json map (toscaJson) first element found by name (elementName) note that this method could update the received argument toscaJson
730      *
731      * @param toscaJson
732      * @param elementName
733      */
734     public static void removeElementFromJsonMap(Map<String, Object> toscaJson, String elementName) {
735         for (Entry<String, Object> entry : toscaJson.entrySet()) {
736             String key = entry.getKey();
737             Object value = entry.getValue();
738             if (key.equals(elementName)) {
739                 toscaJson.remove(elementName);
740                 return;
741             } else if (value instanceof Map) {
742                 removeElementFromJsonMap((Map<String, Object>) value, elementName);
743             }
744         }
745     }
746 }