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