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