Catalog alignment
[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
173         private Constants() {}
174     }
175
176     public enum ResultStatusEnum {
177         ELEMENT_NOT_FOUND, GENERAL_ERROR, OK, INVALID_PROPERTY_DEFAULT_VALUE, INVALID_PROPERTY_TYPE, INVALID_PROPERTY_VALUE, MISSING_ENTRY_SCHEMA_TYPE, INVALID_PROPERTY_NAME
178     }
179
180     public enum ToscaElementTypeEnum {
181         BOOLEAN, STRING, MAP, LIST, ALL
182     }
183
184     @SuppressWarnings("unchecked")
185     private static void handleElementNameNotFound(String elementName, Object elementValue, ToscaElementTypeEnum elementType, List<Object> returnedList) {
186         if (elementValue instanceof Map) {
187             ImportUtils.findToscaElements((Map<String, Object>) elementValue, elementName, elementType, returnedList);
188         } else if (elementValue instanceof List) {
189             ImportUtils.findAllToscaElementsInList((List<Object>) elementValue, elementName, elementType, returnedList);
190         }
191     }
192
193     @SuppressWarnings("unchecked")
194     private static void addFoundElementAccordingToItsType(String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList, Object elementValue) {
195
196         if (elementValue instanceof Boolean) {
197             if (elementType == ToscaElementTypeEnum.BOOLEAN || elementType == ToscaElementTypeEnum.ALL) {
198                 returnedList.add(elementValue);
199             }
200         }
201
202         else if (elementValue instanceof String) {
203             if (elementType == ToscaElementTypeEnum.STRING || elementType == ToscaElementTypeEnum.ALL) {
204                 returnedList.add(elementValue);
205             }
206         } else if (elementValue instanceof Map) {
207             if (elementType == ToscaElementTypeEnum.MAP || elementType == ToscaElementTypeEnum.ALL) {
208                 returnedList.add(elementValue);
209             }
210             ImportUtils.findToscaElements((Map<String, Object>) elementValue, elementName, elementType, returnedList);
211
212         } else if (elementValue instanceof List) {
213             if (elementType == ToscaElementTypeEnum.LIST || elementType == ToscaElementTypeEnum.ALL) {
214                 returnedList.add(elementValue);
215             }
216             ImportUtils.findAllToscaElementsInList((List<Object>) elementValue, elementName, elementType, returnedList);
217
218         }
219         // For Integer, Double etc...
220         else if (elementType == ToscaElementTypeEnum.ALL && elementValue != null) {
221             returnedList.add(String.valueOf(elementValue));
222         }
223     }
224
225     private static void findAllToscaElementsInList(List<Object> list, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) {
226         list.forEach(elementValue -> handleElementNameNotFound(elementName, elementValue, elementType, returnedList));
227     }
228
229     public static Either<Object, ResultStatusEnum> findToscaElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum elementName, ToscaElementTypeEnum elementType) {
230         List<Object> foundElements = new ArrayList<>();
231         ImportUtils.findToscaElements(toscaJson, elementName.getElementName(), elementType, foundElements);
232         if (!isEmpty(foundElements)) {
233             return Either.left(foundElements.get(0));
234         }
235         return Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
236     }
237
238     /**
239      * Recursively searches for all tosca elements with key equals to elementName and value equals to elementType. <br>
240      * Returns Either element with:<br>
241      * List with all value if values found<br>
242      * Or ELEMENT_NOT_FOUND ActionStatus
243      *
244      * @param toscaJson
245      * @return
246      */
247     public static Either<List<Object>, ResultStatusEnum> findToscaElements(Map<String, Object> toscaJson, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) {
248         Either<List<Object>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
249         String skipKey = null;
250         if (toscaJson.containsKey(elementName)) {
251             skipKey = handleFoundElement(toscaJson, elementName, elementType, returnedList);
252         }
253
254
255         Iterator<Entry<String, Object>> keyValItr = toscaJson.entrySet().iterator();
256         while (keyValItr.hasNext()) {
257             Entry<String, Object> keyValEntry = keyValItr.next();
258             if (!String.valueOf(keyValEntry.getKey()).equals(skipKey)) {
259                 handleElementNameNotFound(elementName, keyValEntry.getValue(), elementType, returnedList);
260             }
261         }
262
263         if (!isEmpty(returnedList)) {
264             returnedElement = Either.left(returnedList);
265         }
266
267         return returnedElement;
268     }
269
270     private static String handleFoundElement(Map<String, Object> toscaJson, String elementName, ToscaElementTypeEnum elementType, List<Object> returnedList) {
271         Object elementValue = toscaJson.get(elementName);
272         addFoundElementAccordingToItsType(elementName, elementType, returnedList, elementValue);
273         return elementName;
274
275     }
276
277     @SuppressWarnings("unchecked")
278     public static <T> Either<List<T>, ResultStatusEnum> findFirstToscaListElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum toscaTagName) {
279         Either<List<T>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
280         Either<Object, ResultStatusEnum> findFirstToscaElement = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.LIST);
281         if (findFirstToscaElement.isLeft()) {
282             returnedElement = Either.left((List<T>) findFirstToscaElement.left().value());
283         }
284         return returnedElement;
285
286     }
287
288     @SuppressWarnings("unchecked")
289     public static <T> Either<Map<String, T>, ResultStatusEnum> findFirstToscaMapElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum toscaTagName) {
290         Either<Map<String, T>, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
291         Either<Object, ResultStatusEnum> findFirstToscaElement = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.MAP);
292         if (findFirstToscaElement.isLeft()) {
293             returnedElement = Either.left((Map<String, T>) findFirstToscaElement.left().value());
294         }
295         return returnedElement;
296
297     }
298
299     public static Either<String, ResultStatusEnum> findFirstToscaStringElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum toscaTagName) {
300         Either<String, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
301         Either<Object, ResultStatusEnum> findFirstToscaElements = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.STRING);
302         if (findFirstToscaElements.isLeft()) {
303             returnedElement = Either.left((String) findFirstToscaElements.left().value());
304         }
305         return returnedElement;
306     }
307
308     /**
309      * searches for first Tosca in Json map (toscaJson) boolean element by name (toscaTagName) returns found element or ELEMENT_NOT_FOUND status
310      *
311      * @param toscaJson
312      * @param toscaTagName
313      * @return
314      */
315     public static Either<String, ResultStatusEnum> findFirstToscaBooleanElement(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum toscaTagName) {
316         Either<String, ResultStatusEnum> returnedElement = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
317         Either<Object, ResultStatusEnum> findFirstToscaElements = findToscaElement(toscaJson, toscaTagName, ToscaElementTypeEnum.BOOLEAN);
318         if (findFirstToscaElements.isLeft()) {
319             returnedElement = Either.left(String.valueOf(findFirstToscaElements.left().value()));
320         }
321         return returnedElement;
322     }
323
324     private static void setPropertyConstraints(Map<String, Object> propertyValue, PropertyDefinition property) {
325         List<PropertyConstraint> constraints = getPropertyConstraints(propertyValue, property.getType());
326         if (CollectionUtils.isNotEmpty(constraints)) {
327             property.setConstraints(constraints);
328         }
329     }
330
331     private static List<PropertyConstraint> getPropertyConstraints(Map<String, Object> propertyValue, String propertyType) {
332         List<Object> propertyFieldConstraints = findCurrentLevelConstraintsElement(propertyValue);
333         if (CollectionUtils.isNotEmpty(propertyFieldConstraints)) {
334             List<PropertyConstraint> constraintList = new ArrayList<>();
335             Type constraintType = new TypeToken<PropertyConstraint>() {
336             }.getType();
337             Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, new PropertyConstraintDeserialiser()).create();
338
339             for (Object constraintJson : propertyFieldConstraints) {
340                 PropertyConstraint propertyConstraint = validateAndGetPropertyConstraint(propertyType, constraintType, gson, constraintJson);
341                 constraintList.add(propertyConstraint);
342             }
343             return constraintList;
344         }
345         return null;
346     }
347
348     private static List<Object> findCurrentLevelConstraintsElement(Map<String, Object> toscaJson) {
349         List<Object> constraints = null;
350         if (toscaJson.containsKey(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName())) {
351             try {
352                 constraints = (List<Object>) toscaJson.get(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName());
353             } catch (ClassCastException e){
354                 throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY_CONSTRAINTS_FORMAT, toscaJson.get(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName()).toString());
355             }
356         }
357         return constraints;
358
359     }
360
361     private static PropertyConstraint validateAndGetPropertyConstraint(String propertyType, Type constraintType, Gson gson, Object constraintJson) {
362         PropertyConstraint propertyConstraint;
363         try{
364             propertyConstraint = gson.fromJson(gson.toJson(constraintJson), constraintType);
365         } catch (ClassCastException|JsonParseException e){
366             throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY_CONSTRAINTS_FORMAT, constraintJson.toString());
367         }
368         if(propertyConstraint!= null && propertyConstraint instanceof ValidValuesConstraint){
369             try {
370                 ((ValidValuesConstraint)propertyConstraint).validateType(propertyType);
371             } catch (ConstraintValueDoNotMatchPropertyTypeException e) {
372                 BeEcompErrorManager.getInstance().logInternalFlowError("GetInitializedPropertyConstraint",
373                         e.getMessage(), BeEcompErrorManager.ErrorSeverity.ERROR);
374                 throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY_CONSTRAINTS, ConstraintType.VALID_VALUES.name(),
375                         ((ValidValuesConstraint) propertyConstraint).getValidValues().toString(), propertyType);
376             }
377         }
378         return propertyConstraint;
379     }
380
381     public static PropertyDefinition createModuleProperty(Map<String, Object> propertyValue) {
382
383         PropertyDefinition propertyDef = new PropertyDefinition();
384         setField(propertyValue, TypeUtils.ToscaTagNamesEnum.TYPE, propertyDef::setType);
385         setFieldBoolean(propertyValue, ToscaTagNamesEnum.REQUIRED, req -> propertyDef.setRequired(Boolean.parseBoolean(req)));
386         setField(propertyValue, TypeUtils.ToscaTagNamesEnum.DESCRIPTION, propertyDef::setDescription);
387
388         setJsonStringField(propertyValue, TypeUtils.ToscaTagNamesEnum.DEFAULT_VALUE, propertyDef.getType(), propertyDef::setDefaultValue);
389         setJsonStringField(propertyValue, TypeUtils.ToscaTagNamesEnum.VALUE, propertyDef.getType(), propertyDef::setValue);
390
391         setFieldBoolean(propertyValue, TypeUtils.ToscaTagNamesEnum.IS_PASSWORD, pass -> propertyDef.setPassword(Boolean.parseBoolean(pass)));
392         setField(propertyValue, TypeUtils.ToscaTagNamesEnum.STATUS, propertyDef::setStatus);
393         setScheme(propertyValue, propertyDef);
394         setPropertyConstraints(propertyValue, propertyDef);
395
396         return propertyDef;
397     }
398
399
400     private static void setJsonStringField(Map<String, Object> propertyValue, ToscaTagNamesEnum elementName, String type, Consumer<String> setter) {
401         Either<Object, ResultStatusEnum> eitherValue = ImportUtils.findToscaElement(propertyValue, elementName, ToscaElementTypeEnum.ALL);
402         if (eitherValue.isLeft()) {
403             String propertyJsonStringValue = getPropertyJsonStringValue(eitherValue.left().value(), type);
404             setter.accept(propertyJsonStringValue);
405         }
406     }
407
408
409
410     public static Annotation createModuleAnnotation(Map<String, Object> annotationMap, AnnotationTypeOperations annotationTypeOperations) {
411         String parsedAnnotationType = findFirstToscaStringElement(annotationMap, TypeUtils.ToscaTagNamesEnum.TYPE).left().value();
412         AnnotationTypeDefinition annotationTypeObject = annotationTypeOperations.getLatestType(parsedAnnotationType);
413         if (annotationTypeObject != null) {
414             Annotation annotation = new Annotation();
415             ImportUtils.setField(annotationMap, TypeUtils.ToscaTagNamesEnum.TYPE, annotation::setType);
416             ImportUtils.setField(annotationMap, TypeUtils.ToscaTagNamesEnum.DESCRIPTION, annotation::setDescription);
417             Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = getProperties(annotationMap);
418             modifyPropertiesKeysToProperForm(properties, annotation);
419             return annotation;
420         }
421         return null;
422     }
423
424     private static Either<Boolean, ResponseFormat> modifyPropertiesKeysToProperForm(Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties, Annotation annotation) {
425         Either<Boolean, ResponseFormat> result = Either.left(true);
426         if (properties.isLeft()) {
427             List<PropertyDataDefinition> propertiesList = new ArrayList<>();
428             Map<String, PropertyDefinition> value = properties.left().value();
429             if (value != null) {
430                 for (Entry<String, PropertyDefinition> entry : value.entrySet()) {
431                     String name = entry.getKey();
432                     if (!PROPERTY_NAME_PATTERN_IGNORE_LENGTH.matcher(name).matches()) {
433                         log.debug("The property with invalid name {} occurred upon import resource {}. ", name, annotation.getName());
434                         result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromResultStatusEnum(ResultStatusEnum.INVALID_PROPERTY_NAME, JsonPresentationFields.PROPERTY)));
435                     }
436                     PropertyDefinition propertyDefinition = entry.getValue();
437                     propertyDefinition.setValue(propertyDefinition.getName());
438                     propertyDefinition.setName(name);
439                     propertiesList.add(propertyDefinition);
440                 }
441             }
442             annotation.setProperties(propertiesList);
443         }
444         else if (properties.right().value() != ResultStatusEnum.ELEMENT_NOT_FOUND) {
445             result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromResultStatusEnum(properties
446                     .right()
447                     .value(), JsonPresentationFields.PROPERTY)));
448         }
449         return result;
450     }
451
452     public static InputDefinition createModuleInput(Map<String, Object> inputValue, AnnotationTypeOperations annotationTypeOperations) {
453
454         InputDefinition inputDef = new InputDefinition();
455         ImportUtils.setField(inputValue, TypeUtils.ToscaTagNamesEnum.TYPE, inputDef::setType);
456         ImportUtils.setFieldBoolean(inputValue, ToscaTagNamesEnum.REQUIRED, req -> inputDef.setRequired(Boolean.parseBoolean(req)));
457         ImportUtils.setField(inputValue, TypeUtils.ToscaTagNamesEnum.DESCRIPTION, inputDef::setDescription);
458
459         setJsonStringField(inputValue, TypeUtils.ToscaTagNamesEnum.DEFAULT_VALUE, inputDef.getType(), inputDef::setDefaultValue);
460
461         ImportUtils.setFieldBoolean(inputValue, TypeUtils.ToscaTagNamesEnum.IS_PASSWORD, pass -> inputDef.setPassword(Boolean.parseBoolean(pass)));
462         ImportUtils.setField(inputValue, TypeUtils.ToscaTagNamesEnum.STATUS, inputDef::setStatus);
463         ImportUtils.setField(inputValue, TypeUtils.ToscaTagNamesEnum.LABEL, inputDef::setLabel);
464         ImportUtils.setFieldBoolean(inputValue, TypeUtils.ToscaTagNamesEnum.HIDDEN, hidden -> inputDef.setHidden(Boolean.parseBoolean(hidden)));
465         ImportUtils.setFieldBoolean(inputValue, TypeUtils.ToscaTagNamesEnum.IMMUTABLE, immutable -> inputDef.setImmutable(Boolean.parseBoolean(immutable)));
466
467         ImportUtils.setScheme(inputValue, inputDef);
468         ImportUtils.setPropertyConstraints(inputValue, inputDef);
469
470         return parseAnnotationsAndAddItToInput(inputDef, inputValue, annotationTypeOperations);
471
472     }
473
474
475     public static InputDefinition parseAnnotationsAndAddItToInput(InputDefinition inputDef, Map<String, Object> inputValue, AnnotationTypeOperations annotationTypeOperations){
476         Function<String, Annotation> elementGenByName = ImportUtils::createAnnotation;
477         Function<Map<String, Object>, Annotation> func = annotation -> createModuleAnnotation(annotation, annotationTypeOperations);
478         return getElements(inputValue, TypeUtils.ToscaTagNamesEnum.ANNOTATIONS, elementGenByName, func).
479                 left().map( annotations -> modifyInputWithAnnotations(inputDef, annotations)).
480                 left().on(err -> { log.error("Parsing annotations or adding them to the PropertyDataDefinition object failed");
481                                     return inputDef;});
482     }
483
484     private static InputDefinition modifyInputWithAnnotations(InputDefinition inputDef, Map<String, Annotation> annotationsMap) {
485         setAnnotationsName(annotationsMap);
486         inputDef.setAnnotationsToInput(annotationsMap.values());
487         return inputDef;
488     }
489
490
491     public static PropertyDefinition createModuleAttribute(Map<String, Object> attributeMap) {
492
493         PropertyDefinition attributeDef = new PropertyDefinition();
494         setField(attributeMap, TypeUtils.ToscaTagNamesEnum.TYPE, attributeDef::setType);
495         setField(attributeMap, TypeUtils.ToscaTagNamesEnum.DESCRIPTION, attributeDef::setDescription);
496         setField(attributeMap, TypeUtils.ToscaTagNamesEnum.STATUS, attributeDef::setStatus);
497
498         setJsonStringField(attributeMap, TypeUtils.ToscaTagNamesEnum.DEFAULT_VALUE, attributeDef.getType(), attributeDef::setDefaultValue);
499         setJsonStringField(attributeMap, TypeUtils.ToscaTagNamesEnum.VALUE, attributeDef.getType(), attributeDef::setValue);
500
501         setScheme(attributeMap, attributeDef);
502         return attributeDef;
503     }
504
505     private static void setScheme(Map<String, Object> propertyValue, PropertyDefinition propertyDefinition) {
506         Either<Object, ResultStatusEnum> schemaElementRes = findSchemaElement(propertyValue);
507         if (schemaElementRes.isLeft()) {
508             SchemaDefinition schemaDef = getSchema(schemaElementRes.left().value());
509             propertyDefinition.setSchema(schemaDef);
510         }
511     }
512
513     private static Either<Object,ResultStatusEnum> findSchemaElement(Map<String, Object> propertyValue) {
514         return findToscaElement(propertyValue, TypeUtils.ToscaTagNamesEnum.ENTRY_SCHEMA, ToscaElementTypeEnum.ALL);
515     }
516
517     private static SchemaDefinition getSchema(Object propertyFieldEntryScheme) {
518         SchemaDefinition schema = new SchemaDefinition();
519         if (propertyFieldEntryScheme instanceof String) {
520             String schemaType = (String) propertyFieldEntryScheme;
521             PropertyDefinition schemeProperty = new PropertyDefinition();
522             schemeProperty.setType(schemaType);
523             schema.setProperty(schemeProperty);
524         } else if (propertyFieldEntryScheme instanceof Map) {
525             PropertyDefinition schemeProperty = createModuleProperty((Map<String, Object>) propertyFieldEntryScheme);
526             schema.setProperty(schemeProperty);
527         }
528         return schema;
529     }
530
531     public static void setField(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum tagName, Consumer<String> setter) {
532         Either<String, ResultStatusEnum> fieldStringValue = findFirstToscaStringElement(toscaJson, tagName);
533         if (fieldStringValue.isLeft()) {
534             setter.accept(fieldStringValue.left().value());
535         }
536
537     }
538
539     public static void setFieldBoolean(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum tagName, Consumer<String> setter) {
540         Either<String, ResultStatusEnum> fieldStringValue = findFirstToscaBooleanElement(toscaJson, tagName);
541         if (fieldStringValue.isLeft()) {
542             setter.accept(fieldStringValue.left().value());
543         }
544
545     }
546
547
548     public static Either<Map<String, PropertyDefinition>, ResultStatusEnum> getProperties(Map<String, Object> toscaJson) {
549         Function<String, PropertyDefinition> elementGenByName = ImportUtils::createProperties;
550         Function<Map<String, Object>, PropertyDefinition> func = ImportUtils::createModuleProperty;
551
552         return getElements(toscaJson, TypeUtils.ToscaTagNamesEnum.PROPERTIES, elementGenByName, func);
553
554     }
555
556     public static Either<Map<String, InputDefinition>, ResultStatusEnum> getInputs(Map<String, Object> toscaJson, AnnotationTypeOperations annotationTypeOperations) {
557         Function<String, InputDefinition> elementGenByName = ImportUtils::createInputs;
558         Function<Map<String, Object>, InputDefinition> func = object -> createModuleInput(object, annotationTypeOperations);
559
560         return getElements(toscaJson, TypeUtils.ToscaTagNamesEnum.INPUTS, elementGenByName, func);
561
562     }
563
564     public static Either<Map<String, PropertyDefinition>, ResultStatusEnum> getAttributes(Map<String, Object> toscaJson) {
565         Function<String, PropertyDefinition> elementGenByName = ImportUtils::createAttribute;
566         Function<Map<String, Object>, PropertyDefinition> func = ImportUtils::createModuleAttribute;
567
568         return getElements(toscaJson, TypeUtils.ToscaTagNamesEnum.ATTRIBUTES, elementGenByName, func);
569     }
570
571     public static <T> Either<Map<String, T>, ResultStatusEnum>  getElements(Map<String, Object> toscaJson, TypeUtils.ToscaTagNamesEnum elementTagName, Function<String, T> elementGenByName,
572                                                                            Function<Map<String, Object>, T> func) {
573         Either<Map<String, T>, ResultStatusEnum> eitherResult = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
574         Either<Map<String, Object>, ResultStatusEnum> toscaAttributes = findFirstToscaMapElement(toscaJson, elementTagName);
575         if (toscaAttributes.isLeft()) {
576             Map<String, Object> jsonAttributes = toscaAttributes.left().value();
577             Map<String, T> moduleAttributes = new HashMap<>();
578             Iterator<Entry<String, Object>> propertiesNameValue = jsonAttributes.entrySet().iterator();
579             while (propertiesNameValue.hasNext()) {
580                 Entry<String, Object> attributeNameValue = propertiesNameValue.next();
581                 if (attributeNameValue.getValue() instanceof Map) {
582                     @SuppressWarnings("unchecked")
583                     T attribute = func.apply((Map<String, Object>) attributeNameValue.getValue());
584                     if (attribute != null){
585                         moduleAttributes.put(String.valueOf(attributeNameValue.getKey()), attribute);
586                     }
587                 }
588                 else {
589                     T element = elementGenByName.apply(String.valueOf(attributeNameValue.getValue()));
590                     moduleAttributes.put(String.valueOf(attributeNameValue.getKey()), element);
591                 }
592             }
593             if (moduleAttributes.size() > 0) {
594                 eitherResult = Either.left(moduleAttributes);
595             }
596
597         }
598         return eitherResult;
599
600     }
601
602     private static PropertyDefinition createAttribute(String name) {
603         PropertyDefinition attribute = new PropertyDefinition();
604
605         attribute.setName(name);
606         return attribute;
607     }
608
609     private static PropertyDefinition createProperties(String name) {
610         PropertyDefinition property = new PropertyDefinition();
611         property.setDefaultValue(name);
612         property.setName(name);
613         return property;
614     }
615
616
617
618     private static InputDefinition createInputs(String name) {
619         InputDefinition input = new InputDefinition();
620
621         input.setName(name);
622         return input;
623     }
624
625     private static Annotation createAnnotation(String name) {
626         Annotation annotation = new Annotation();
627         annotation.setName(name);
628         return annotation;
629     }
630
631
632
633     public static Either<List<HeatParameterDefinition>, ResultStatusEnum> getHeatParameters(Map<String, Object> heatData, String artifactType) {
634
635         Either<List<HeatParameterDefinition>, ResultStatusEnum> eitherResult = Either.right(ResultStatusEnum.ELEMENT_NOT_FOUND);
636         Either<Map<String, Object>, ResultStatusEnum> toscaProperties = findFirstToscaMapElement(heatData, TypeUtils.ToscaTagNamesEnum.PARAMETERS);
637         if (toscaProperties.isLeft()) {
638             Map<String, Object> jsonProperties = toscaProperties.left().value();
639             List<HeatParameterDefinition> moduleProperties = new ArrayList<>();
640             Iterator<Entry<String, Object>> propertiesNameValue = jsonProperties.entrySet().iterator();
641             while (propertiesNameValue.hasNext()) {
642                 Entry<String, Object> propertyNameValue = propertiesNameValue.next();
643                 if (propertyNameValue.getValue() instanceof Map || propertyNameValue.getValue() instanceof List) {
644                     if (!artifactType.equals(ArtifactTypeEnum.HEAT_ENV.getType())) {
645                         @SuppressWarnings("unchecked")
646                         Either<HeatParameterDefinition, ResultStatusEnum> propertyStatus = createModuleHeatParameter((Map<String, Object>) propertyNameValue.getValue());
647                         if (propertyStatus.isRight()) {
648                             return Either.right(propertyStatus.right().value());
649                         }
650                         HeatParameterDefinition property = propertyStatus.left().value();
651                         property.setName(String.valueOf(propertyNameValue.getKey()));
652                         moduleProperties.add(property);
653                     } else {
654                         addHeatParamDefinition(moduleProperties, propertyNameValue, true);
655                     }
656                 } else {
657                     addHeatParamDefinition(moduleProperties, propertyNameValue, false);
658                 }
659
660             }
661
662             if (!isEmpty(moduleProperties)) {
663                 eitherResult = Either.left(moduleProperties);
664             }
665
666         }
667         return eitherResult;
668
669     }
670
671     private static void addHeatParamDefinition(List<HeatParameterDefinition> moduleProperties, Entry<String, Object> propertyNameValue, boolean isJson) {
672         HeatParameterDefinition property = new HeatParameterDefinition();
673         Object value = propertyNameValue.getValue();
674         if (value != null) {
675             property.setDefaultValue(isJson ? new Gson().toJson(value) : StringEscapeUtils.escapeJava(String.valueOf(value)));
676         }
677         property.setName(String.valueOf(propertyNameValue.getKey()));
678         moduleProperties.add(property);
679     }
680
681     private static Either<HeatParameterDefinition, ResultStatusEnum> createModuleHeatParameter(Map<String, Object> propertyValue) {
682         HeatParameterDefinition propertyDef = new HeatParameterDefinition();
683         String type;
684         Either<String, ResultStatusEnum> propertyFieldType = findFirstToscaStringElement(propertyValue, TypeUtils.ToscaTagNamesEnum.TYPE);
685         if (propertyFieldType.isLeft()) {
686             type = propertyFieldType.left().value();
687             propertyDef.setType(type);
688         } else {
689             return Either.right(ResultStatusEnum.INVALID_PROPERTY_TYPE);
690         }
691         Either<String, ResultStatusEnum> propertyFieldDescription = findFirstToscaStringElement(propertyValue, TypeUtils.ToscaTagNamesEnum.DESCRIPTION);
692         if (propertyFieldDescription.isLeft()) {
693             propertyDef.setDescription(propertyFieldDescription.left().value());
694         }
695
696         Either<Object, ResultStatusEnum> propertyFieldDefaultVal = findToscaElement(propertyValue, TypeUtils.ToscaTagNamesEnum.DEFAULT_VALUE, ToscaElementTypeEnum.ALL);
697         if (propertyFieldDefaultVal.isLeft()) {
698             if (propertyFieldDefaultVal.left().value() == null) {
699                 return Either.right(ResultStatusEnum.INVALID_PROPERTY_VALUE);
700             }
701             Object value = propertyFieldDefaultVal.left().value();
702             String defaultValue = type.equals(HeatParameterType.JSON.getType()) ? new Gson().toJson(value) : StringEscapeUtils.escapeJava(String.valueOf(value));
703             propertyDef.setDefaultValue(defaultValue);
704             propertyDef.setCurrentValue(defaultValue);
705         }
706
707         return Either.left(propertyDef);
708     }
709     public static boolean containsGetInput(Object propValue) {
710         String value = getPropertyJsonStringValue(propValue, ToscaPropertyType.MAP.getType());
711         return value != null && value.contains(TypeUtils.ToscaTagNamesEnum.GET_INPUT.getElementName());
712     }
713
714     public static String getPropertyJsonStringValue(Object value, String type) {
715         Gson gson = new Gson();
716         if (type == null) {
717             return null;
718         }
719         ToscaPropertyType validType = ToscaPropertyType.isValidType(type);
720         if (validType == null ||  validType == ToscaPropertyType.JSON || validType == ToscaPropertyType.MAP || validType == ToscaPropertyType.LIST) {
721             return gson.toJson(value);
722         }
723         return value.toString();
724     }
725
726     /**
727      * removes from Json map (toscaJson) first element found by name (elementName) note that this method could update the received argument toscaJson
728      *
729      * @param toscaJson
730      * @param elementName
731      */
732     public static void removeElementFromJsonMap(Map<String, Object> toscaJson, String elementName) {
733         for (Entry<String, Object> entry : toscaJson.entrySet()) {
734             String key = entry.getKey();
735             Object value = entry.getValue();
736             if (key.equals(elementName)) {
737                 toscaJson.remove(elementName);
738                 return;
739             } else if (value instanceof Map) {
740                 removeElementFromJsonMap((Map<String, Object>) value, elementName);
741             }
742         }
743     }
744 }