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