2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * Modifications copyright (c) 2019 Nokia
20 * ================================================================================
23 package org.openecomp.sdc.be.components.impl;
25 import fj.data.Either;
26 import org.apache.commons.lang3.tuple.ImmutablePair;
27 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
28 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
29 import org.openecomp.sdc.be.components.impl.model.ToscaTypeImportData;
30 import org.openecomp.sdc.be.config.BeEcompErrorManager;
31 import org.openecomp.sdc.be.dao.api.ActionStatus;
32 import org.openecomp.sdc.be.datatypes.elements.ToscaTypeDataDefinition;
33 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
34 import org.openecomp.sdc.be.impl.ComponentsUtils;
35 import org.openecomp.sdc.be.model.*;
36 import org.openecomp.sdc.be.model.normatives.ToscaTypeMetadata;
37 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
38 import org.openecomp.sdc.be.model.operations.api.TypeOperations;
39 import org.openecomp.sdc.be.model.operations.impl.PropertyOperation;
40 import org.openecomp.sdc.common.log.wrappers.Logger;
41 import org.openecomp.sdc.exception.ResponseFormat;
42 import org.springframework.stereotype.Component;
43 import org.yaml.snakeyaml.Yaml;
46 import java.util.Map.Entry;
47 import java.util.function.BiFunction;
48 import java.util.function.Consumer;
49 import java.util.function.Function;
50 import java.util.stream.Collectors;
52 import static java.util.stream.Collectors.toList;
54 @Component("commonImportManager")
55 public class CommonImportManager {
57 private static final Logger log = Logger.getLogger(CommonImportManager.class.getName());
59 private final ComponentsUtils componentsUtils;
60 private final PropertyOperation propertyOperation;
62 public CommonImportManager(ComponentsUtils componentsUtils, PropertyOperation propertyOperation) {
63 this.componentsUtils = componentsUtils;
64 this.propertyOperation = propertyOperation;
67 public static void setProperties(Map<String, Object> toscaJson, Consumer<List<PropertyDefinition>> consumer) {
68 consumer.accept(getProperties(toscaJson));
71 private static List<PropertyDefinition> getProperties(Map<String, Object> toscaJson) {
72 List<PropertyDefinition> values = null;
73 Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = ImportUtils.getProperties(toscaJson);
75 if (properties.isLeft()) {
76 values = new ArrayList<>();
77 Map<String, PropertyDefinition> propertiesMap = properties.left().value();
78 if (propertiesMap != null && !propertiesMap.isEmpty()) {
80 for (Entry<String, PropertyDefinition> entry : propertiesMap.entrySet()) {
81 String propName = entry.getKey();
82 PropertyDefinition propertyDefinition = entry.getValue();
83 PropertyDefinition newPropertyDefinition = new PropertyDefinition(propertyDefinition);
84 newPropertyDefinition.setName(propName);
85 values.add(newPropertyDefinition);
93 protected void setPropertiesMap(Map<String, Object> toscaJson, Consumer<Map<String, PropertyDefinition>> consumer) {
94 final List<PropertyDefinition> properties = getProperties(toscaJson);
95 if (properties != null) {
96 Map<String, PropertyDefinition> collect = properties.stream()
97 .collect(Collectors.toMap(PropertyDefinition::getName, Function.identity()));
98 consumer.accept(collect);
102 public interface ICreateElementType<T1, T2, T3> {
103 T3 createElement(T1 firstArg, T2 secondArg);
106 protected <T> Either<List<T>, ActionStatus> createElementTypesFromYml(String elementTypesYml, ICreateElementType<String, Map<String, Object>, T> createApi) {
108 List<T> elementTypes;
109 Map<String, Object> toscaJson = convertToFieldMap(elementTypesYml);
110 if (toscaJson==null) {
111 return Either.right(ActionStatus.INVALID_YAML_FILE);
113 elementTypes = createElementTypesFromToscaJsonMap(createApi, toscaJson);
114 return Either.left(elementTypes);
117 @SuppressWarnings("unchecked")
118 private Map<String, Object> convertToFieldMap(String elementTypesYml) {
119 Map<String, Object> toscaJson = null;
121 toscaJson = (Map<String, Object>) new Yaml().load(elementTypesYml);
122 } catch (Exception e) {
123 log.debug("Failed to yaml file {}", elementTypesYml, e);
129 protected <T extends ToscaDataDefinition> List<T> createTypesFromToscaJsonMap(
130 BiFunction<String, Map<String, Object>, T> createApi, Map<String, Object> toscaJson) {
131 List<T> elementTypes = new ArrayList<>();
133 for (Entry<String, Object> elementTypeNameDataEntry : toscaJson.entrySet()) {
134 String elementTypeName = elementTypeNameDataEntry.getKey();
135 Map<String, Object> elementTypeJsonData = (Map<String, Object>) elementTypeNameDataEntry.getValue();
136 T elementDefinition = createApi.apply(elementTypeName, elementTypeJsonData);
137 elementTypes.add(elementDefinition);
142 protected <T> List<T> createElementTypesFromToscaJsonMap(
143 ICreateElementType<String, Map<String, Object>, T> createApi, Map<String, Object> toscaJson) {
144 List<T> elementTypes = new ArrayList<>();
146 for (Entry<String, Object> elementTypeNameDataEntry : toscaJson.entrySet()) {
147 String elementTypeName = elementTypeNameDataEntry.getKey();
148 Map<String, Object> elementTypeJsonData = (Map<String, Object>) elementTypeNameDataEntry.getValue();
149 T elementDefinition = createApi.createElement(elementTypeName, elementTypeJsonData);
150 elementTypes.add(elementDefinition);
155 protected <T> Map<String, T> createElementTypesMapFromToscaJsonMap(
156 ICreateElementType<String, Map<String, Object>, T> createApi, Map<String, Object> toscaJson) {
157 Map<String, T> elementTypesMap = new HashMap<>();
159 Iterator<Entry<String, Object>> elementTypesEntryItr = toscaJson.entrySet().iterator();
160 while (elementTypesEntryItr.hasNext()) {
161 Entry<String, Object> elementTypeNameDataEntry = elementTypesEntryItr.next();
162 String elementTypeName = elementTypeNameDataEntry.getKey();
163 Map<String, Object> elementTypeJsonData = (Map<String, Object>) elementTypeNameDataEntry.getValue();
164 T elementDefinition = createApi.createElement(elementTypeName, elementTypeJsonData);
165 elementTypesMap.put(elementTypeName, elementDefinition);
167 return elementTypesMap;
170 protected <F> void setField(Map<String, Object> toscaJson, String fieldName, Consumer<F> setter) {
171 if (toscaJson.containsKey(fieldName)) {
172 F fieldValue = (F) toscaJson.get(fieldName);
173 setter.accept(fieldValue);
177 public enum ElementTypeEnum {
178 POLICY_TYPE, GROUP_TYPE, DATA_TYPE, CAPABILITY_TYPE, INTERFACE_LIFECYCLE_TYPE, RELATIONSHIP_TYPE
181 private ActionStatus convertFromStorageResponseForElementType(StorageOperationStatus status, ElementTypeEnum elementTypeEnum) {
183 switch (elementTypeEnum) {
185 ret = componentsUtils.convertFromStorageResponseForGroupType(status);
188 ret = componentsUtils.convertFromStorageResponseForDataType(status);
190 case CAPABILITY_TYPE:
191 ret = componentsUtils.convertFromStorageResponseForCapabilityType(status);
193 case INTERFACE_LIFECYCLE_TYPE:
194 ret = componentsUtils.convertFromStorageResponseForLifecycleType(status);
196 case RELATIONSHIP_TYPE:
197 ret = componentsUtils.convertFromStorageResponseForRelationshipType(status);
200 ret = componentsUtils.convertFromStorageResponse(status);
206 private <T> ResponseFormat getResponseFormatForElementType(ActionStatus actionStatus, ElementTypeEnum elementTypeEnum, T elementTypeDefinition) {
208 switch (elementTypeEnum) {
210 ret = componentsUtils.getResponseFormatByGroupType(actionStatus, (GroupTypeDefinition) elementTypeDefinition);
213 ret = componentsUtils.getResponseFormatByPolicyType(actionStatus, (PolicyTypeDefinition) elementTypeDefinition);
216 ret = componentsUtils.getResponseFormatByDataType(actionStatus, (DataTypeDefinition) elementTypeDefinition, null);
218 case CAPABILITY_TYPE:
219 ret = componentsUtils.getResponseFormatByCapabilityType(actionStatus, (CapabilityTypeDefinition) elementTypeDefinition);
223 ret = componentsUtils.getResponseFormat(actionStatus);
229 private <T extends ToscaDataDefinition> List<ImmutablePair<T, Boolean>> createTypesByDao(List<T> elementTypesToCreate,
230 TypeOperations<T> typeOperations) {
231 List<ImmutablePair<T, Boolean>> createdElementTypes = new ArrayList<>();
232 for (T newTypeDefinition : elementTypesToCreate) {
234 String typeName = newTypeDefinition.getType();
235 T existingDefinition = typeOperations.getLatestType(typeName);
236 if (existingDefinition == null /*new type*/) {
237 typeOperations.addType(newTypeDefinition);
239 if (typeOperations.isSameType(newTypeDefinition, existingDefinition)) {
240 propertyOperation.getJanusGraphGenericDao().rollback();
241 createdElementTypes.add(new ImmutablePair<>(newTypeDefinition, null));
244 typeOperations.updateType(existingDefinition, newTypeDefinition);
247 propertyOperation.getJanusGraphGenericDao().commit();
248 createdElementTypes.add(new ImmutablePair<>(newTypeDefinition, true));
249 } catch (Exception e) {
250 propertyOperation.getJanusGraphGenericDao().rollback();
251 createdElementTypes.add(new ImmutablePair<>(newTypeDefinition, false));
255 return createdElementTypes;
258 protected <T> Either<List<ImmutablePair<T, Boolean>>, ResponseFormat> createElementTypesByDao(List<T> elementTypesToCreate,
259 Function<T, Either<ActionStatus, ResponseFormat>> validator, Function<T, ImmutablePair<ElementTypeEnum, String>> elementInfoGetter,
260 Function<String, Either<T, StorageOperationStatus>> elementFetcher, Function<T, Either<T, StorageOperationStatus>> elementAdder,
261 BiFunction<T, T, Either<T, StorageOperationStatus>> elementUpgrader) {
263 List<ImmutablePair<T, Boolean>> createdElementTypes = new ArrayList<>();
265 Either<List<ImmutablePair<T, Boolean>>, ResponseFormat> eitherResult = Either.left(createdElementTypes);
266 Iterator<T> elementTypeItr = elementTypesToCreate.iterator();
269 while (elementTypeItr.hasNext()) {
270 T elementType = elementTypeItr.next();
271 eitherResult = handleType(elementType, validator, elementInfoGetter, elementFetcher, elementAdder, elementUpgrader)
273 .map(elem -> append(createdElementTypes, elem));
275 if (eitherResult.isRight()) {
279 if(!elementTypeItr.hasNext()) {
280 log.info("all {} were created successfully!!!", elementType);
285 eitherResult = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
289 if (eitherResult.isLeft()) {
290 propertyOperation.getJanusGraphGenericDao().commit();
293 propertyOperation.getJanusGraphGenericDao().rollback();
300 private static <T> List<T> append(List<T> list, T value) {
306 private <T> Either<ImmutablePair<T, Boolean>, ResponseFormat> handleType(T elementType,
307 Function<T, Either<ActionStatus, ResponseFormat>> validator, Function<T, ImmutablePair<ElementTypeEnum, String>> elementInfoGetter,
308 Function<String, Either<T, StorageOperationStatus>> elementFetcher, Function<T, Either<T, StorageOperationStatus>> elementAdder,
309 BiFunction<T, T, Either<T, StorageOperationStatus>> elementUpgrader) {
311 final ImmutablePair<ElementTypeEnum, String> elementInfo = elementInfoGetter.apply(elementType);
312 ElementTypeEnum elementTypeEnum = elementInfo.left;
313 String elementName = elementInfo.right;
315 Either<ActionStatus, ResponseFormat> validateElementType = validator.apply(elementType);
316 if (validateElementType.isRight()) {
317 ResponseFormat responseFormat = validateElementType.right().value();
318 log.debug("Failed in validation of element type: {}. Response is {}", elementType, responseFormat.getFormattedMessage());
319 return Either.right(responseFormat);
322 log.info("send {} : {} to dao for create", elementTypeEnum, elementName);
324 Either<T, StorageOperationStatus> findElementType = elementFetcher.apply(elementName);
325 if (findElementType.isRight()) {
326 StorageOperationStatus status = findElementType.right().value();
327 log.debug("searched {} finished with result:{}", elementTypeEnum, status);
328 if (status != StorageOperationStatus.NOT_FOUND) {
329 ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(status, elementTypeEnum), elementTypeEnum, elementType);
330 return Either.right(responseFormat);
332 return addElementType(elementType, elementAdder, elementTypeEnum, elementName);
336 if (elementUpgrader != null) {
337 return updateElementType(elementType, elementUpgrader, elementTypeEnum, elementName, findElementType.left().value());
340 // mshitrit Once GroupType Versions are supported add
342 log.debug("{} : {} already exists.", elementTypeEnum, elementName);
343 return Either.left(new ImmutablePair<>(elementType, false));
349 private <T> Either<ImmutablePair<T, Boolean>, ResponseFormat> addElementType(T elementType, Function<T, Either<T, StorageOperationStatus>> elementAdder, ElementTypeEnum elementTypeEnum, String elementName) {
350 Either<T, StorageOperationStatus> dataModelResponse = elementAdder.apply(elementType);
352 if (dataModelResponse.isRight()) {
353 BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError("Create {}", elementTypeEnum.name());
354 log.debug("failed to create {}: {}", elementTypeEnum, elementName);
355 if (dataModelResponse.right().value() != StorageOperationStatus.OK) {
356 ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(dataModelResponse.right().value(), elementTypeEnum), elementTypeEnum, elementType);
358 return Either.right(responseFormat);
360 return Either.left(new ImmutablePair<>(elementType, false));
363 log.debug("{} : {} was created successfully.", elementTypeEnum, elementName);
364 return Either.left(new ImmutablePair<>(elementType, true));
369 private <T> Either<ImmutablePair<T, Boolean>, ResponseFormat> updateElementType(T elementType, BiFunction<T, T, Either<T, StorageOperationStatus>> elementUpgrader,
370 ElementTypeEnum elementTypeEnum, String elementName, T existingElementType) {
371 Either<T, StorageOperationStatus> upgradeResponse = elementUpgrader.apply(elementType, existingElementType);
372 if (upgradeResponse.isRight()) {
373 StorageOperationStatus status = upgradeResponse.right().value();
374 if (status == StorageOperationStatus.OK) {
375 return Either.left(new ImmutablePair<>(elementType, false));
377 ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(upgradeResponse.right().value(), elementTypeEnum), elementTypeEnum, elementType);
378 return Either.right(responseFormat);
381 log.debug("{} : {} was upgraded successfully.", elementTypeEnum, elementName);
382 return Either.left(new ImmutablePair<>(elementType, true));
387 public <T extends ToscaTypeDataDefinition> Either<List<ImmutablePair<T, Boolean>>, ResponseFormat> createElementTypes(ToscaTypeImportData toscaTypeImportData, Function<String, Either<List<T>, ActionStatus>> elementTypeFromYmlCreater,
388 Function<List<T>, Either<List<ImmutablePair<T, Boolean>>, ResponseFormat>> elementTypeDaoCreater) {
389 Either<List<T>, ActionStatus> elementTypes = elementTypeFromYmlCreater.apply(toscaTypeImportData.getToscaTypesYml());
392 .map(err -> componentsUtils.getResponseFormat(err, ""))
394 .map(toscaTypes -> enrichTypesWithNonToscaMetadata(toscaTypes, toscaTypeImportData.getToscaTypeMetadata()))
396 .bind(elementTypeDaoCreater::apply);
399 public <T extends ToscaDataDefinition> List<ImmutablePair<T, Boolean>> createElementTypes(String toscaTypesYml,
400 BiFunction<String, Map<String, Object>, T> createApi,
401 TypeOperations<T> typeOperations) {
402 Map<String, Object> fieldMap = convertToFieldMap(toscaTypesYml);
403 if (fieldMap==null) {
404 throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML_FILE);
406 List<T> elementTypes = createTypesFromToscaJsonMap(createApi, fieldMap);
407 return createTypesByDao(elementTypes, typeOperations);
410 private <T extends ToscaTypeDataDefinition> List<T> enrichTypesWithNonToscaMetadata(List<T> toscaTypes, Map<String, ToscaTypeMetadata> toscaTypeMetadata) {
411 return toscaTypes.stream()
412 .map(toscaType -> setNonToscaMetaDataOnType(toscaTypeMetadata, toscaType))
416 private <T extends ToscaTypeDataDefinition> T setNonToscaMetaDataOnType(Map<String, ToscaTypeMetadata> toscaTypeMetadata, T toscaTypeDefinition) {
417 String toscaType = toscaTypeDefinition.getType();
418 ToscaTypeMetadata typeMetaData = toscaTypeMetadata.get(toscaType);
419 if (typeMetaData == null) {
420 log.debug("failing while trying to associate metadata for type {}. type not exist", toscaType);
421 throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
423 toscaTypeDefinition.setIcon(typeMetaData.getIcon());
424 toscaTypeDefinition.setName(typeMetaData.getDisplayName());
425 return toscaTypeDefinition;
428 public <T> Either<List<ImmutablePair<T, Boolean>>, ResponseFormat> createElementTypes(String elementTypesYml, Function<String, Either<List<T>, ActionStatus>> elementTypeFromYmlCreater,
429 Function<List<T>, Either<List<ImmutablePair<T, Boolean>>, ResponseFormat>> elementTypeDaoCreater, ElementTypeEnum elementTypeEnum) {
431 Either<List<T>, ActionStatus> elementTypes = elementTypeFromYmlCreater.apply(elementTypesYml);
432 if (elementTypes.isRight()) {
433 ActionStatus status = elementTypes.right().value();
434 ResponseFormat responseFormat = getResponseFormatForElementType(status, elementTypeEnum, null);
435 return Either.right(responseFormat);
437 return elementTypeDaoCreater.apply(elementTypes.left().value());