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