92e1d8f39275e717fe8fe4cce3c88d6a0defe018
[sdc.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19
20 package org.openecomp.core.converter.impl.pnfd.parser;
21
22 import static org.openecomp.core.converter.pnfd.model.PnfTransformationToken.CONVERSIONS;
23 import static org.openecomp.core.converter.pnfd.model.PnfTransformationToken.DESCRIPTION;
24 import static org.openecomp.core.converter.pnfd.model.PnfTransformationToken.FROM;
25 import static org.openecomp.core.converter.pnfd.model.PnfTransformationToken.NAME;
26 import static org.openecomp.core.converter.pnfd.model.PnfTransformationToken.PROPERTIES;
27 import static org.openecomp.core.converter.pnfd.model.PnfTransformationToken.QUERY;
28 import static org.openecomp.core.converter.pnfd.model.PnfTransformationToken.TO;
29 import static org.openecomp.core.converter.pnfd.model.PnfTransformationToken.TRANSFORMATION_FOR;
30
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Objects;
38 import java.util.Optional;
39 import java.util.Set;
40 import java.util.stream.Collectors;
41 import org.apache.commons.collections.CollectionUtils;
42 import org.apache.commons.collections.MapUtils;
43 import org.openecomp.core.converter.impl.pnfd.strategy.ReplaceConversionStrategy;
44 import org.openecomp.core.converter.pnfd.model.ConversionDefinition;
45 import org.openecomp.core.converter.pnfd.model.ConversionQuery;
46 import org.openecomp.core.converter.pnfd.model.Transformation;
47 import org.openecomp.core.converter.pnfd.model.TransformationBlock;
48 import org.openecomp.core.converter.pnfd.model.TransformationProperty;
49 import org.openecomp.core.converter.pnfd.model.TransformationPropertyType;
50 import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum;
51 import org.openecomp.sdc.logging.api.Logger;
52 import org.openecomp.sdc.logging.api.LoggerFactory;
53
54 /**
55  * Handles YAML from/to {@link Transformation} conversions
56  */
57 public class TransformationYamlParser {
58
59     private static final Logger LOGGER = LoggerFactory.getLogger(TransformationYamlParser.class);
60
61     private TransformationYamlParser() {
62
63     }
64
65     /**
66      * Parses the given YAML object to a {@link Transformation} instance.
67      * @param transformationYaml      the YAML object representing a transformation
68      * @return
69      *  A new instance of {@link Transformation}.
70      */
71     public static Optional<Transformation> parse(final Map<String, Object> transformationYaml) {
72         final Transformation transformation = new Transformation();
73         final Optional<String> name = parseStringAttribute(NAME.getName(), transformationYaml);
74         if (!name.isPresent()) {
75             LOGGER.warn("Invalid '{}' value in transformation '{}'", NAME.getName(), transformationYaml.toString());
76         }
77         transformation.setName(name.orElse(null));
78         transformation.setDescription(parseStringAttribute(DESCRIPTION.getName(), transformationYaml).orElse(null));
79         transformation.setPropertySet(readProperties(transformationYaml));
80
81         final String block = parseStringAttribute(TRANSFORMATION_FOR.getName(), transformationYaml).orElse(null);
82         final Optional<TransformationBlock> transformationBlockOptional = TransformationBlock.parse(block);
83         if (transformationBlockOptional.isPresent()) {
84             final TransformationBlock transformationBlock = transformationBlockOptional.get();
85             transformation.setBlock(transformationBlock);
86             parseTransformationBlock(transformationBlock, transformation, transformationYaml);
87         } else {
88             LOGGER.warn("Invalid '{}' value in transformation '{}'", TRANSFORMATION_FOR.getName(),
89                 transformationYaml.toString());
90         }
91
92         if (transformation.isValid()) {
93             return Optional.of(transformation);
94         }
95
96         return Optional.empty();
97     }
98
99     private static Set<TransformationProperty> readProperties(final Map<String, Object> transformationYaml) {
100         final Map<String, Object> propertyMap = (Map<String, Object>) transformationYaml.get(PROPERTIES.getName());
101         if (MapUtils.isEmpty(propertyMap)) {
102             return Collections.emptySet();
103         }
104
105         final Set<TransformationProperty> propertySet = new HashSet<>();
106
107         propertyMap.forEach((key, value) -> {
108             final TransformationPropertyType transformationPropertyType = TransformationPropertyType.parse(key)
109                 .orElse(null);
110
111             if(transformationPropertyType != null) {
112                 if (value instanceof String) {
113                     propertySet.add(new TransformationProperty<>(transformationPropertyType, (String) value));
114                 } else if (value instanceof Boolean) {
115                     propertySet.add(new TransformationProperty<>(transformationPropertyType, (Boolean) value));
116                 } else if (value instanceof Integer) {
117                     propertySet.add(new TransformationProperty<>(transformationPropertyType, (Integer) value));
118                 } else {
119                     propertySet.add(new TransformationProperty<>(transformationPropertyType, value));
120                 }
121             }
122         });
123
124         return propertySet;
125     }
126
127     private static void parseTransformationBlock(final TransformationBlock transformationBlock,
128                                                  final Transformation transformationReference,
129                                                  final Map<String, Object> transformationYaml) {
130         if (transformationBlock == TransformationBlock.CUSTOM_NODE_TYPE) {
131             parseCustomNodeTypeBlock(transformationReference, transformationYaml);
132             return;
133         }
134
135         ConversionQueryYamlParser.parse(transformationYaml.get(QUERY.getName()))
136             .ifPresent(transformationReference::setConversionQuery);
137
138         transformationReference.setConversionDefinitionList(parseConversions(transformationYaml));
139     }
140
141     private static void parseCustomNodeTypeBlock(final Transformation transformationReference,
142                                                  final Map<String, Object> transformationYaml) {
143         final Object fromAttribute = transformationYaml.get(FROM.getName());
144         if (!(fromAttribute instanceof String)) {
145             return;
146         }
147         final String from = parseStringAttribute(FROM.getName(), transformationYaml).orElse(null);
148
149         final Object toAttribute = transformationYaml.get(TO.getName());
150         if (!(toAttribute instanceof String)) {
151             return;
152         }
153         final String to = parseStringAttribute(TO.getName(), transformationYaml).orElse(null);
154
155         final HashMap<String, String> transformationQuery = new HashMap<>();
156         transformationQuery.put(ToscaTagNamesEnum.DERIVED_FROM.getElementName(), from);
157         transformationReference.setConversionQuery(new ConversionQuery(transformationQuery));
158
159         final List<ConversionDefinition> conversionDefinitionList = new ArrayList<>();
160         final HashMap<String, String> conversionDefinitionQuery = new HashMap<>();
161         conversionDefinitionQuery.put(ToscaTagNamesEnum.TYPE.getElementName(), null);
162         ConversionDefinition conversionDefinition = new ConversionDefinition(new ConversionQuery(conversionDefinitionQuery)
163             , ToscaTagNamesEnum.TYPE.getElementName(), new ReplaceConversionStrategy(from, to));
164         conversionDefinitionList.add(conversionDefinition);
165         transformationReference.setConversionDefinitionList(conversionDefinitionList);
166     }
167
168     private static List<ConversionDefinition> parseConversions(final Map<String, Object> conversionYaml) {
169         final List<Object> conversionList = (List<Object>) conversionYaml.get(CONVERSIONS.getName());
170
171         if (CollectionUtils.isEmpty(conversionList)) {
172             return Collections.emptyList();
173         }
174
175         return conversionList.stream()
176             .map(conversion -> ConversionDefinitionYamlParser.parse((Map<String, Object>) conversion).orElse(null))
177             .filter(Objects::nonNull)
178             .collect(Collectors.toList());
179     }
180
181     private static Optional<String> parseStringAttribute(final String attribute, final Map<String, Object> transformationYaml) {
182         try {
183             return Optional.of((String) transformationYaml.get(attribute));
184         } catch (final Exception e) {
185             LOGGER.warn("Could not parse the String '{}' in transformation '{}'",
186                 attribute, transformationYaml.toString(), e);
187             return Optional.empty();
188         }
189     }
190
191 }